diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9e448dfe63..0f1e6d9138 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,7 +6,6 @@ on: env: HOMEBREW_DEVELOPER: 1 HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_GITHUB_ACTIONS_BIG_SUR_TESTING: 1 # TODO: remove when Big Sur is released. jobs: tests: if: github.repository == 'Homebrew/brew' diff --git a/.gitignore b/.gitignore index 728456b5f2..ca8d5f18ab 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ # Ignore Bundler files **/.bundle/bin **/.bundle/cache +**/vendor/bundle/ruby/*/bundler.lock **/vendor/bundle/ruby/*/bin **/vendor/bundle/ruby/*/build_info/ **/vendor/bundle/ruby/*/cache @@ -127,6 +128,7 @@ **/vendor/bundle/ruby/*/gems/rspec-mocks-*/ **/vendor/bundle/ruby/*/gems/rspec-retry-*/ **/vendor/bundle/ruby/*/gems/rspec-support-*/ +**/vendor/bundle/ruby/*/gems/rspec-sorbet-*/ **/vendor/bundle/ruby/*/gems/rspec-wait-*/ **/vendor/bundle/ruby/*/gems/rubocop-1*/ **/vendor/bundle/ruby/*/gems/rubocop-ast-*/ diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index 7b09968858..358bafc5a7 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -18,6 +18,7 @@ AllCops: - 'Homebrew/sorbet/rbi/gems/**/*.rbi' - 'Homebrew/sorbet/rbi/hidden-definitions/**/*.rbi' - 'Homebrew/sorbet/rbi/todo.rbi' + - 'Homebrew/sorbet/rbi/upstream.rbi' - 'Homebrew/bin/*' - 'Homebrew/vendor/**/*' @@ -69,7 +70,7 @@ Naming/HeredocDelimiterNaming: Naming/MethodName: IgnoredPatterns: - - '\AHEAD\?\Z' + - '\A(fetch_)?HEAD\?\Z' # Allow dashes in filenames. Naming/FileName: @@ -108,7 +109,9 @@ Style/HashTransformValues: # Allow for license expressions Style/HashAsLastArrayItem: Exclude: - - 'Taps/*/*/{Formula/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/Formula/*.rb' + - '**/Formula/*.rb' # Enabled now LineLength is lowish. Style/IfUnlessModifier: @@ -118,6 +121,8 @@ Style/IfUnlessModifier: Style/NumericLiterals: MinDigits: 7 Strict: true + Exclude: + - '**/Brewfile' # Zero-prefixed octal literals are widely used and understood. Style/NumericLiteralPrefix: @@ -161,11 +166,17 @@ Performance/CaseWhenSplat: Performance/Caller: 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. Style/DisableCopsWithinSourceCodeDirective: Enabled: true Include: - - 'Taps/*/*/{Formula/,Casks/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' # make our hashes consistent Layout/HashAlignment: @@ -175,7 +186,9 @@ Layout/HashAlignment: # `system` is a special case and aligns on second argument, so allow this for formulae. Layout/ArgumentAlignment: Exclude: - - 'Taps/*/*/{Formula/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/Formula/*.rb' + - '**/Formula/*.rb' # this is a bit less "floaty" Layout/CaseIndentation: @@ -197,6 +210,12 @@ Layout/RescueEnsureAlignment: Lint/AmbiguousBlockAssociation: Enabled: false +Lint/DuplicateBranch: + Exclude: + - 'Taps/*/*/*.rb' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' + # needed for lazy_object magic Naming/MemoizedInstanceVariableName: Exclude: @@ -206,7 +225,9 @@ Naming/MemoizedInstanceVariableName: # TODO: fix these as `ruby -w` complains about them. Lint/AmbiguousRegexpLiteral: Exclude: - - 'Taps/*/*/{Formula/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/Formula/*.rb' + - '**/Formula/*.rb' # useful for metaprogramming in RSpec Lint/ConstantDefinitionInBlock: @@ -216,30 +237,46 @@ Lint/ConstantDefinitionInBlock: # so many of these in formulae and can't be autocorrected Lint/ParenthesesAsGroupedExpression: Exclude: - - 'Taps/*/*/{Formula/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/Formula/*.rb' + - '**/Formula/*.rb' # Most metrics don't make sense to apply for casks/formulae/taps. Metrics/AbcSize: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' Metrics/BlockLength: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' Metrics/ClassLength: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' Metrics/CyclomaticComplexity: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' Metrics/MethodLength: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' Metrics/ModuleLength: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' Metrics/PerceivedComplexity: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' # allow those that are standard # TODO: try to remove some of these @@ -280,7 +317,9 @@ Layout/LineLength: Sorbet/FalseSigil: Exclude: - - 'Taps/**/*.rb' + - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' - 'Homebrew/test/**/Casks/**/*.rb' Sorbet/StrictSigil: @@ -297,15 +336,9 @@ Sorbet/ConstantsFromStrings: Style/AccessModifierDeclarations: Enabled: false -# don't group nicely documented or private attr_readers +# Conflicts with type signatures on `attr_*`s. Style/AccessorGrouping: - Exclude: - - 'Homebrew/formula.rb' - - 'Homebrew/formulary.rb' - - 'Homebrew/migrator.rb' - - 'Homebrew/resource.rb' - - 'Homebrew/system_command.rb' - - 'Homebrew/tap.rb' + Enabled: false # make rspec formatting more flexible Style/BlockDelimiters: @@ -322,6 +355,8 @@ Style/ClassVars: Style/Documentation: Exclude: - 'Taps/**/*' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' - '**/*.rbi' Style/DocumentationMethod: @@ -332,9 +367,12 @@ Style/DocumentationMethod: Style/FrozenStringLiteralComment: EnforcedStyle: always Exclude: - - 'Taps/*/*/{Formula,Casks,}/*.rb' + - 'Taps/*/*/*.rb' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' - 'Homebrew/test/**/Casks/**/*.rb' - '**/*.rbi' + - '**/Brewfile' # TODO: remove this when possible. Style/GlobalVars: @@ -344,7 +382,9 @@ Style/GlobalVars: # potential for errors in formulae too high with this Style/GuardClause: Exclude: - - 'Taps/*/*/{Formula/,Casks/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' # avoid hash rockets where possible Style/HashSyntax: @@ -353,7 +393,9 @@ Style/HashSyntax: # so many of these in formulae and can't be autocorrected Style/StringConcatenation: Exclude: - - 'Taps/*/*/{Formula/,Casks/,}*.rb' + - 'Taps/*/*/*.rb' + - '/**/{Formula,Casks}/*.rb' + - '**/{Formula,Casks}/*.rb' # ruby style guide favorite Style/StringLiterals: diff --git a/Library/Homebrew/Gemfile b/Library/Homebrew/Gemfile index 57014db73f..00681d456d 100644 --- a/Library/Homebrew/Gemfile +++ b/Library/Homebrew/Gemfile @@ -10,6 +10,7 @@ gem "ronn", require: false gem "rspec", require: false gem "rspec-its", require: false gem "rspec-retry", require: false +gem "rspec-sorbet", require: false gem "rspec-wait", require: false gem "rubocop", require: false gem "simplecov", require: false diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index f5081f7a50..8163765500 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -44,7 +44,7 @@ GEM method_source (1.0.0) mime-types (3.3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2020.0512) + mime-types-data (3.2020.1104) mini_portile2 (2.4.0) minitest (5.14.2) mustache (1.1.1) @@ -95,39 +95,42 @@ GEM rspec-support (~> 3.10.0) rspec-retry (0.6.2) rspec-core (> 3.3) + rspec-sorbet (1.7.0) + sorbet + sorbet-runtime rspec-support (3.10.0) rspec-wait (0.0.9) rspec (>= 3, < 4) - rubocop (1.2.0) + rubocop (1.3.1) parallel (~> 1.10) parser (>= 2.7.1.5) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8) rexml - rubocop-ast (>= 1.0.1) + rubocop-ast (>= 1.1.1) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 2.0) rubocop-ast (1.1.1) parser (>= 2.7.1.5) - rubocop-performance (1.8.1) - rubocop (>= 0.87.0) + rubocop-performance (1.9.0) + rubocop (>= 0.90.0, < 2.0) rubocop-ast (>= 0.4.0) rubocop-rspec (2.0.0) rubocop (~> 1.0) rubocop-ast (>= 1.1.0) rubocop-sorbet (0.5.1) rubocop - ruby-macho (2.2.0) + ruby-macho (2.5.0) ruby-progressbar (1.10.1) simplecov (0.19.1) docile (~> 1.1) simplecov-html (~> 0.11) simplecov-html (0.12.3) - sorbet (0.5.6042) - sorbet-static (= 0.5.6042) - sorbet-runtime (0.5.6040) + sorbet (0.5.6076) + sorbet-static (= 0.5.6076) + sorbet-runtime (0.5.6076) 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) colorize sorbet (~> 0.5.5) @@ -142,14 +145,14 @@ GEM thor (>= 0.19.2) thor (1.0.1) thread_safe (0.3.6) - tzinfo (1.2.7) + tzinfo (1.2.8) thread_safe (~> 0.1) unf (0.1.4) unf_ext unf_ext (0.0.7.7) unicode-display_width (1.7.0) webrobots (0.1.2) - zeitwerk (2.4.0) + zeitwerk (2.4.1) PLATFORMS ruby @@ -167,6 +170,7 @@ DEPENDENCIES rspec rspec-its rspec-retry + rspec-sorbet rspec-wait rubocop rubocop-performance diff --git a/Library/Homebrew/PATH.rb b/Library/Homebrew/PATH.rb index 20b83d0d36..a69709e9c9 100644 --- a/Library/Homebrew/PATH.rb +++ b/Library/Homebrew/PATH.rb @@ -67,13 +67,9 @@ class PATH sig { params(other: T.untyped).returns(T::Boolean) } def ==(other) - if other.respond_to?(:to_ary) && to_ary == other.to_ary - true - elsif other.respond_to?(:to_str) && to_str == other.to_str - true - else + (other.respond_to?(:to_ary) && to_ary == other.to_ary) || + (other.respond_to?(:to_str) && to_str == other.to_str) || false - end end sig { returns(T::Boolean) } diff --git a/Library/Homebrew/bintray.rb b/Library/Homebrew/bintray.rb index ea50ed3479..7277cfdebc 100644 --- a/Library/Homebrew/bintray.rb +++ b/Library/Homebrew/bintray.rb @@ -8,6 +8,8 @@ require "json" # # @api private class Bintray + extend T::Sig + include Context API_URL = "https://api.bintray.com" @@ -15,6 +17,7 @@ class Bintray class Error < RuntimeError end + sig { returns(String) } def inspect "#" end diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index 9bcccedbca..43ab29a917 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -164,7 +164,7 @@ rescue BuildError => e if e.formula.head? || e.formula.deprecated? || e.formula.disabled? $stderr.puts <<~EOS Please create pull requests instead of asking for help on Homebrew's GitHub, - Discourse, Twitter or any other official channels. + Twitter or any other official channels. EOS end diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb index f7c4274874..94b928211c 100644 --- a/Library/Homebrew/build.rb +++ b/Library/Homebrew/build.rb @@ -53,11 +53,7 @@ class Build def expand_reqs formula.recursive_requirements do |dependent, req| build = effective_build_options_for(dependent) - if req.prune_from_option?(build) - Requirement.prune - elsif req.prune_if_build_and_not_dependent?(dependent, formula) - Requirement.prune - elsif req.test? + if req.prune_from_option?(build) || req.prune_if_build_and_not_dependent?(dependent, formula) || req.test? Requirement.prune end end @@ -66,14 +62,12 @@ class Build def expand_deps formula.recursive_dependencies do |dependent, dep| build = effective_build_options_for(dependent) - if dep.prune_from_option?(build) - Dependency.prune - elsif dep.prune_if_build_and_not_dependent?(dependent, formula) + if dep.prune_from_option?(build) || + dep.prune_if_build_and_not_dependent?(dependent, formula) || + (dep.test? && !dep.build?) Dependency.prune elsif dep.build? Dependency.keep_but_prune_recursive_deps - elsif dep.test? - Dependency.prune end end end diff --git a/Library/Homebrew/build_environment.rb b/Library/Homebrew/build_environment.rb index 6b4e7f0529..4f80b74adb 100644 --- a/Library/Homebrew/build_environment.rb +++ b/Library/Homebrew/build_environment.rb @@ -1,34 +1,44 @@ -# typed: false +# typed: true # frozen_string_literal: true # Settings for the build environment. # # @api private class BuildEnvironment + extend T::Sig + + sig { params(settings: Symbol).void } def initialize(*settings) - @settings = Set.new(*settings) + @settings = Set.new(settings) end + sig { params(args: T::Enumerable[Symbol]).returns(T.self_type) } def merge(*args) @settings.merge(*args) self end + sig { params(o: Symbol).returns(T.self_type) } def <<(o) @settings << o self end + sig { returns(T::Boolean) } def std? @settings.include? :std end + sig { returns(T::Boolean) } def userpaths? @settings.include? :userpaths end # DSL for specifying build environment settings. module DSL + extend T::Sig + + sig { params(settings: Symbol).returns(BuildEnvironment) } def env(*settings) @env ||= BuildEnvironment.new @env.merge(settings) @@ -50,16 +60,18 @@ class BuildEnvironment ].freeze private_constant :KEYS + sig { params(env: T.untyped).returns(T::Array[String]) } def self.keys(env) KEYS & env.keys end + sig { params(env: T.untyped, f: IO).void } def self.dump(env, f = $stdout) keys = self.keys(env) keys -= %w[CC CXX OBJC OBJCXX] if env["CC"] == env["HOMEBREW_CC"] keys.each do |key| - value = env[key] + value = env.fetch(key) s = +"#{key}: #{value}" case key when "CC", "CXX", "LD" diff --git a/Library/Homebrew/cask/artifact/abstract_artifact.rb b/Library/Homebrew/cask/artifact/abstract_artifact.rb index 50c2b325e5..9d6e5d1381 100644 --- a/Library/Homebrew/cask/artifact/abstract_artifact.rb +++ b/Library/Homebrew/cask/artifact/abstract_artifact.rb @@ -7,6 +7,8 @@ module Cask # # @api private class AbstractArtifact + extend T::Sig + include Comparable extend Predicable @@ -132,6 +134,7 @@ module Cask cask.config end + sig { returns(String) } def to_s "#{summarize} (#{self.class.english_name})" end diff --git a/Library/Homebrew/cask/artifact/abstract_uninstall.rb b/Library/Homebrew/cask/artifact/abstract_uninstall.rb index baa8467a37..51505e70c9 100644 --- a/Library/Homebrew/cask/artifact/abstract_uninstall.rb +++ b/Library/Homebrew/cask/artifact/abstract_uninstall.rb @@ -15,6 +15,8 @@ module Cask # # @api private class AbstractUninstall < AbstractArtifact + extend T::Sig + ORDERED_DIRECTIVES = [ :early_script, :launchctl, @@ -53,6 +55,7 @@ module Cask directives.to_h end + sig { returns(String) } def summarize to_h.flat_map { |key, val| Array(val).map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ") end @@ -128,6 +131,7 @@ module Cask end end + sig { returns(String) } def automation_access_instructions "Enable Automation Access for “Terminal > System Events” in " \ "“System Preferences > Security > Privacy > Automation” if you haven't already." diff --git a/Library/Homebrew/cask/artifact/artifact.rb b/Library/Homebrew/cask/artifact/artifact.rb index f6b350a82d..8d083a1bd5 100644 --- a/Library/Homebrew/cask/artifact/artifact.rb +++ b/Library/Homebrew/cask/artifact/artifact.rb @@ -12,6 +12,9 @@ module Cask # # @api private class Artifact < Moved + extend T::Sig + + sig { returns(String) } def self.english_name "Generic Artifact" end diff --git a/Library/Homebrew/cask/artifact/mdimporter.rb b/Library/Homebrew/cask/artifact/mdimporter.rb index 226a01e1cc..5a4ce2d052 100644 --- a/Library/Homebrew/cask/artifact/mdimporter.rb +++ b/Library/Homebrew/cask/artifact/mdimporter.rb @@ -9,6 +9,9 @@ module Cask # # @api private class Mdimporter < Moved + extend T::Sig + + sig { returns(String) } def self.english_name "Spotlight metadata importer" end diff --git a/Library/Homebrew/cask/artifact/moved.rb b/Library/Homebrew/cask/artifact/moved.rb index 6acb7d7827..bd9287ad29 100644 --- a/Library/Homebrew/cask/artifact/moved.rb +++ b/Library/Homebrew/cask/artifact/moved.rb @@ -9,6 +9,9 @@ module Cask # # @api private class Moved < Relocated + extend T::Sig + + sig { returns(String) } def self.english_description "#{english_name}s" end diff --git a/Library/Homebrew/cask/artifact/prefpane.rb b/Library/Homebrew/cask/artifact/prefpane.rb index aed47644e1..8dc2df4559 100644 --- a/Library/Homebrew/cask/artifact/prefpane.rb +++ b/Library/Homebrew/cask/artifact/prefpane.rb @@ -9,6 +9,9 @@ module Cask # # @api private class Prefpane < Moved + extend T::Sig + + sig { returns(String) } def self.english_name "Preference Pane" end diff --git a/Library/Homebrew/cask/artifact/qlplugin.rb b/Library/Homebrew/cask/artifact/qlplugin.rb index e0c26a6dc8..d50956d8ca 100644 --- a/Library/Homebrew/cask/artifact/qlplugin.rb +++ b/Library/Homebrew/cask/artifact/qlplugin.rb @@ -9,6 +9,9 @@ module Cask # # @api private class Qlplugin < Moved + extend T::Sig + + sig { returns(String) } def self.english_name "QuickLook Plugin" end diff --git a/Library/Homebrew/cask/artifact/relocated.rb b/Library/Homebrew/cask/artifact/relocated.rb index 5c9dd0dbd5..f5e61e9677 100644 --- a/Library/Homebrew/cask/artifact/relocated.rb +++ b/Library/Homebrew/cask/artifact/relocated.rb @@ -12,6 +12,8 @@ module Cask # # @api private class Relocated < AbstractArtifact + extend T::Sig + def self.from_args(cask, *args) source_string, target_hash = args @@ -49,6 +51,7 @@ module Cask end end + sig { returns(String) } def summarize target_string = @target_string.empty? ? "" : " -> #{@target_string}" "#{@source_string}#{target_string}" diff --git a/Library/Homebrew/cask/artifact/stage_only.rb b/Library/Homebrew/cask/artifact/stage_only.rb index c67cac6d3b..b475b00a86 100644 --- a/Library/Homebrew/cask/artifact/stage_only.rb +++ b/Library/Homebrew/cask/artifact/stage_only.rb @@ -9,16 +9,20 @@ module Cask # # @api private class StageOnly < AbstractArtifact + extend T::Sig + def self.from_args(cask, *args) raise CaskInvalidError.new(cask.token, "'stage_only' takes only a single argument: true") if args != [true] new(cask) end + sig { returns(T::Array[T::Boolean]) } def to_a [true] end + sig { returns(String) } def summarize "true" end diff --git a/Library/Homebrew/cask/artifact/suite.rb b/Library/Homebrew/cask/artifact/suite.rb index a236a602e0..043b4f0b9e 100644 --- a/Library/Homebrew/cask/artifact/suite.rb +++ b/Library/Homebrew/cask/artifact/suite.rb @@ -9,10 +9,14 @@ module Cask # # @api private class Suite < Moved + extend T::Sig + + sig { returns(String) } def self.english_name "App Suite" end + sig { returns(Symbol) } def self.dirmethod :appdir end diff --git a/Library/Homebrew/cask/artifact/symlinked.rb b/Library/Homebrew/cask/artifact/symlinked.rb index 68e8dbe181..bb423e69d4 100644 --- a/Library/Homebrew/cask/artifact/symlinked.rb +++ b/Library/Homebrew/cask/artifact/symlinked.rb @@ -9,10 +9,14 @@ module Cask # # @api private class Symlinked < Relocated + extend T::Sig + + sig { returns(String) } def self.link_type_english_name "Symlink" end + sig { returns(String) } def self.english_description "#{english_name} #{link_type_english_name}s" end diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 7e2297becc..a9603a50e8 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -13,6 +13,8 @@ module Cask # # @api private class Audit + extend T::Sig + extend Predicable attr_reader :cask, :download @@ -117,6 +119,7 @@ module Cask end end + sig { returns(String) } def summary summary = ["audit for #{cask}: #{result}"] @@ -416,6 +419,7 @@ module Cask core_tap.formula_names end + sig { returns(String) } def core_formula_url "#{core_tap.default_remote}/blob/HEAD/Formula/#{cask.token}.rb" end diff --git a/Library/Homebrew/cask/cache.rb b/Library/Homebrew/cask/cache.rb index 1cd57f9060..911a4eb833 100644 --- a/Library/Homebrew/cask/cache.rb +++ b/Library/Homebrew/cask/cache.rb @@ -6,9 +6,10 @@ module Cask # # @api private module Cache - module_function + extend T::Sig - def path + sig { returns(Pathname) } + def self.path @path ||= HOMEBREW_CACHE/"Cask" end end diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index 8858922a0b..da73e98755 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -12,6 +12,8 @@ module Cask # # @api private class Cask + extend T::Sig + extend Enumerable extend Forwardable extend Searchable @@ -20,7 +22,7 @@ module Cask attr_reader :token, :sourcefile_path, :config, :default_config def self.each(&block) - return to_enum unless block_given? + return to_enum unless block Tap.flat_map(&:cask_files).each do |f| 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) } end + sig { returns(T::Array[[String, String]]) } def timestamped_versions Pathname.glob(metadata_timestamped_path(version: "*", timestamp: "*")) .map { |p| p.relative_path_from(p.parent.parent) } @@ -89,6 +92,7 @@ module Cask !versions.empty? end + sig { returns(T.nilable(Time)) } def install_time _, time = timestamped_versions.last return unless time diff --git a/Library/Homebrew/cask/cask_loader.rb b/Library/Homebrew/cask/cask_loader.rb index 8ec015a931..b49ad9275e 100644 --- a/Library/Homebrew/cask/cask_loader.rb +++ b/Library/Homebrew/cask/cask_loader.rb @@ -90,6 +90,8 @@ module Cask # Loads a cask from a URI. class FromURILoader < FromPathLoader + extend T::Sig + def self.can_load?(ref) uri_regex = ::URI::DEFAULT_PARSER.make_regexp 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 + sig { params(url: T.any(URI::Generic, String)).void } def initialize(url) @url = URI(url) 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. class NullLoader < FromPathLoader + extend T::Sig + def self.can_load?(*) true end + sig { params(ref: T.any(String, Pathname)).void } def initialize(ref) token = File.basename(ref, ".rb") super CaskLoader.default_path(token) diff --git a/Library/Homebrew/cask/caskroom.rb b/Library/Homebrew/cask/caskroom.rb index ab9c1b4dc0..8d91d4582f 100644 --- a/Library/Homebrew/cask/caskroom.rb +++ b/Library/Homebrew/cask/caskroom.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "utils/user" @@ -8,13 +8,15 @@ module Cask # # @api private module Caskroom - module_function + extend T::Sig - def path + sig { returns(Pathname) } + def self.path @path ||= HOMEBREW_PREFIX.join("Caskroom") end - def ensure_caskroom_exists + sig { void } + def self.ensure_caskroom_exists return if path.exist? sudo = !path.parent.writable? @@ -30,7 +32,8 @@ module Cask SystemCommand.run("/usr/bin/chgrp", args: ["admin", path], sudo: sudo) end - def casks(config: nil) + sig { params(config: T.nilable(Config)).returns(T::Array[Cask]) } + def self.casks(config: nil) return [] unless path.exist? Pathname.glob(path.join("*")).sort.select(&:directory?).map do |path| diff --git a/Library/Homebrew/cask/cmd.rb b/Library/Homebrew/cask/cmd.rb index 5c62cb73ea..f789cc3748 100644 --- a/Library/Homebrew/cask/cmd.rb +++ b/Library/Homebrew/cask/cmd.rb @@ -38,6 +38,8 @@ module Cask # # @api private class Cmd + extend T::Sig + include Context ALIASES = { @@ -61,11 +63,13 @@ module Cask Cmd::Upgrade => "brew upgrade --cask", }.freeze + sig { returns(String) } def self.description max_command_length = Cmd.commands.map(&:length).max command_lines = Cmd.command_classes .select(&:visible?) + .reject { |command| DEPRECATED_COMMANDS.key?(command) } .map do |klass| " - #{"`#{klass.command_name}`".ljust(max_command_length + 2)} #{klass.short_description}\n" end @@ -75,14 +79,13 @@ module Cask Commands: #{command_lines.join} - See also: `man brew` EOS end def self.parser(&block) Homebrew::CLI::Parser.new do - if block_given? + if block instance_eval(&block) else usage_banner <<~EOS diff --git a/Library/Homebrew/cask/cmd/--cache.rb b/Library/Homebrew/cask/cmd/--cache.rb index 613841f7c3..8a85ba5a85 100644 --- a/Library/Homebrew/cask/cmd/--cache.rb +++ b/Library/Homebrew/cask/cmd/--cache.rb @@ -7,18 +7,24 @@ module Cask # # @api private class Cache < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { returns(String) } def self.description "Display the file used to cache a ." end + sig { returns(String) } def self.command_name "--cache" end + sig { void } def run casks.each do |cask| puts self.class.cached_location(cask) diff --git a/Library/Homebrew/cask/cmd/abstract_command.rb b/Library/Homebrew/cask/cmd/abstract_command.rb index cf4ca79a0d..afa69cc2fa 100644 --- a/Library/Homebrew/cask/cmd/abstract_command.rb +++ b/Library/Homebrew/cask/cmd/abstract_command.rb @@ -9,16 +9,22 @@ module Cask # # @api private class AbstractCommand + extend T::Sig + extend T::Helpers + include Homebrew::Search + sig { returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named nil end + sig { returns(T.nilable(Integer)) } def self.max_named nil end + sig { returns(String) } def self.banner_args if min_named == :cask && max_named != 1 " " @@ -29,13 +35,14 @@ module Cask end end + sig { returns(String) } def self.banner_headline "`#{command_name}` []#{banner_args}" end OPTIONS = [ [: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, }], [:switch, "--require-sha", { @@ -43,7 +50,7 @@ module Cask env: :cask_opts_require_sha, }], [:switch, "--[no-]quarantine", { - description: "Disable/enable quarantining of downloads. Default: enabled", + description: "Disable/enable quarantining of downloads (default: enabled).", env: :cask_opts_quarantine, }], ].freeze @@ -61,7 +68,7 @@ module Cask Cmd.parser do usage_banner banner - instance_eval(&block) if block_given? + instance_eval(&block) if block OPTIONS.each do |option| send(*option) @@ -72,24 +79,29 @@ module Cask end end + sig { returns(String) } def self.command_name @command_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase end + sig { returns(T::Boolean) } def self.abstract? name.split("::").last.match?(/^Abstract[^a-z]/) end + sig { returns(T::Boolean) } def self.visible? true end + sig { returns(String) } def self.help parser.generate_help_text end + sig { returns(String) } def self.short_description - description.split(".").first + description[/\A[^.]*\./] end def self.run(*args) diff --git a/Library/Homebrew/cask/cmd/abstract_internal_command.rb b/Library/Homebrew/cask/cmd/abstract_internal_command.rb index 7ccc3937b7..a0a45e8b1b 100644 --- a/Library/Homebrew/cask/cmd/abstract_internal_command.rb +++ b/Library/Homebrew/cask/cmd/abstract_internal_command.rb @@ -7,10 +7,14 @@ module Cask # # @api private class AbstractInternalCommand < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.command_name super.sub(/^internal_/i, "_") end + sig { returns(T::Boolean) } def self.visible? false end diff --git a/Library/Homebrew/cask/cmd/audit.rb b/Library/Homebrew/cask/cmd/audit.rb index 6deeb84f8e..864625f588 100644 --- a/Library/Homebrew/cask/cmd/audit.rb +++ b/Library/Homebrew/cask/cmd/audit.rb @@ -9,6 +9,9 @@ module Cask # # @api private class Audit < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.description <<~EOS Check for Homebrew coding style violations. This should be run before @@ -37,57 +40,84 @@ module Cask end end + sig { void } 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| - if File.exist?(name) - name - elsif name.count("/") == 1 - Tap.fetch(name).cask_files - else - name - end + next name if File.exist?(name) + next Tap.fetch(name).cask_files if name.count("/") == 1 + + name end casks = casks.map { |c| CaskLoader.load(c, config: Config.from_args(args)) } casks = Cask.to_a if casks.empty? - failed_casks = casks.reject do |cask| - odebug "Auditing Cask #{cask}" - result = Auditor.audit(cask, **options) + results = self.class.audit_casks( + *casks, + 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"] - 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 + self.class.print_annotations(results) + failed_casks = results.reject { |_, result| result[:errors].empty? }.map(&:first) return if failed_casks.empty? raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}" 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 diff --git a/Library/Homebrew/cask/cmd/cat.rb b/Library/Homebrew/cask/cmd/cat.rb index fb79443000..d5d2afdc6a 100644 --- a/Library/Homebrew/cask/cmd/cat.rb +++ b/Library/Homebrew/cask/cmd/cat.rb @@ -7,14 +7,19 @@ module Cask # # @api private class Cat < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { returns(String) } def self.description "Dump raw source of a to the standard output." end + sig { void } def run casks.each do |cask| if Homebrew::EnvConfig.bat? diff --git a/Library/Homebrew/cask/cmd/create.rb b/Library/Homebrew/cask/cmd/create.rb index 7ae14dc7d5..c03b1611ff 100644 --- a/Library/Homebrew/cask/cmd/create.rb +++ b/Library/Homebrew/cask/cmd/create.rb @@ -7,14 +7,19 @@ module Cask # # @api private class Create < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { override.returns(T.nilable(Integer)) } def self.max_named 1 end + sig { returns(String) } def self.description "Creates the given and opens it in an editor." end @@ -25,6 +30,7 @@ module Cask raise UsageError, "Only one cask can be created at a time." end + sig { void } def run cask_token = args.named.first cask_path = CaskLoader.path(cask_token) diff --git a/Library/Homebrew/cask/cmd/doctor.rb b/Library/Homebrew/cask/cmd/doctor.rb index 0c80dcef21..c2565191ad 100644 --- a/Library/Homebrew/cask/cmd/doctor.rb +++ b/Library/Homebrew/cask/cmd/doctor.rb @@ -7,14 +7,19 @@ module Cask # # @api private class Doctor < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(Integer)) } def self.max_named 0 end + sig { returns(String) } def self.description "Checks for configuration issues." end + sig { void } def run require "diagnostic" diff --git a/Library/Homebrew/cask/cmd/edit.rb b/Library/Homebrew/cask/cmd/edit.rb index bea10bf630..ca01e711c3 100644 --- a/Library/Homebrew/cask/cmd/edit.rb +++ b/Library/Homebrew/cask/cmd/edit.rb @@ -7,14 +7,19 @@ module Cask # # @api private class Edit < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { override.returns(T.nilable(Integer)) } def self.max_named 1 end + sig { returns(String) } def self.description "Open the given for editing." end @@ -25,6 +30,7 @@ module Cask raise UsageError, "Only one cask can be edited at a time." end + sig { void } def run exec_editor cask_path rescue CaskUnavailableError => e diff --git a/Library/Homebrew/cask/cmd/fetch.rb b/Library/Homebrew/cask/cmd/fetch.rb index d9b3351832..7add6ae1dc 100644 --- a/Library/Homebrew/cask/cmd/fetch.rb +++ b/Library/Homebrew/cask/cmd/fetch.rb @@ -7,6 +7,9 @@ module Cask # # @api private class Fetch < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end @@ -18,10 +21,12 @@ module Cask end end + sig { returns(String) } def self.description "Downloads remote application files to local cache." end + sig { void } def run require "cask/download" require "cask/installer" diff --git a/Library/Homebrew/cask/cmd/help.rb b/Library/Homebrew/cask/cmd/help.rb index 721ac40842..7a3a2cba4d 100644 --- a/Library/Homebrew/cask/cmd/help.rb +++ b/Library/Homebrew/cask/cmd/help.rb @@ -7,14 +7,19 @@ module Cask # # @api private class Help < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(Integer)) } def self.max_named 1 end + sig { returns(String) } def self.description "Print help for `cask` commands." end + sig { void } def run if args.named.empty? puts Cmd.parser.generate_help_text diff --git a/Library/Homebrew/cask/cmd/home.rb b/Library/Homebrew/cask/cmd/home.rb index 8087f21faa..6beaf0ac2c 100644 --- a/Library/Homebrew/cask/cmd/home.rb +++ b/Library/Homebrew/cask/cmd/home.rb @@ -7,10 +7,14 @@ module Cask # # @api private class Home < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.description "Opens the homepage of the given . If no cask is given, opens the Homebrew homepage." end + sig { void } def run if casks.none? odebug "Opening project homepage" diff --git a/Library/Homebrew/cask/cmd/info.rb b/Library/Homebrew/cask/cmd/info.rb index e4e0797f72..1ffebfa177 100644 --- a/Library/Homebrew/cask/cmd/info.rb +++ b/Library/Homebrew/cask/cmd/info.rb @@ -9,10 +9,14 @@ module Cask # # @api private class Info < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { returns(String) } def self.description "Displays information about the given ." end @@ -42,6 +46,7 @@ module Cask end end + sig { void } def run if args.json == "v1" puts JSON.generate(args.named.to_casks.map(&:to_h)) diff --git a/Library/Homebrew/cask/cmd/install.rb b/Library/Homebrew/cask/cmd/install.rb index a5ad63d19c..c2dc60105f 100644 --- a/Library/Homebrew/cask/cmd/install.rb +++ b/Library/Homebrew/cask/cmd/install.rb @@ -7,10 +7,14 @@ module Cask # # @api private class Install < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { returns(String) } def self.description "Installs the given ." end @@ -30,10 +34,11 @@ module Cask send(*option) end - instance_eval(&block) if block_given? + instance_eval(&block) if block end end + sig { void } def run self.class.install_casks( *casks, diff --git a/Library/Homebrew/cask/cmd/internal_help.rb b/Library/Homebrew/cask/cmd/internal_help.rb index 2091f48f95..3f6476e29a 100644 --- a/Library/Homebrew/cask/cmd/internal_help.rb +++ b/Library/Homebrew/cask/cmd/internal_help.rb @@ -7,14 +7,19 @@ module Cask # # @api private class InternalHelp < AbstractInternalCommand + extend T::Sig + + sig { override.returns(T.nilable(Integer)) } def self.max_named 0 end + sig { returns(String) } def self.description "Print help for unstable internal-use commands." end + sig { void } def run max_command_len = Cmd.commands.map(&:length).max puts "Unstable Internal-use Commands:\n\n" diff --git a/Library/Homebrew/cask/cmd/internal_stanza.rb b/Library/Homebrew/cask/cmd/internal_stanza.rb index 95335690e1..3183588b82 100644 --- a/Library/Homebrew/cask/cmd/internal_stanza.rb +++ b/Library/Homebrew/cask/cmd/internal_stanza.rb @@ -9,6 +9,8 @@ module Cask # # @api private class InternalStanza < AbstractInternalCommand + extend T::Sig + # Syntax # # brew cask _stanza [ --quiet ] [ --table | --yaml ] [ ... ] @@ -24,14 +26,17 @@ module Cask (DSL::ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) + DSL::ARTIFACT_BLOCK_CLASSES.map(&:dsl_key)).freeze + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named 1 end + sig { returns(String) } def self.banner_args " []" end + sig { returns(String) } def self.description <<~EOS Extract and render a specific stanza for the given . @@ -80,6 +85,7 @@ module Cask EOS end + sig { void } def run if ARTIFACTS.include?(stanza) artifact_name = stanza diff --git a/Library/Homebrew/cask/cmd/list.rb b/Library/Homebrew/cask/cmd/list.rb index 859d650a9c..7c780c2464 100644 --- a/Library/Homebrew/cask/cmd/list.rb +++ b/Library/Homebrew/cask/cmd/list.rb @@ -9,6 +9,9 @@ module Cask # # @api private class List < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.description "Lists installed casks or the casks provided in the arguments." end @@ -26,6 +29,7 @@ module Cask end end + sig { void } def run self.class.list_casks( *casks, diff --git a/Library/Homebrew/cask/cmd/outdated.rb b/Library/Homebrew/cask/cmd/outdated.rb index ff35a1f2d6..791f465333 100644 --- a/Library/Homebrew/cask/cmd/outdated.rb +++ b/Library/Homebrew/cask/cmd/outdated.rb @@ -7,6 +7,9 @@ module Cask # # @api private class Outdated < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.description "List the outdated installed casks." end @@ -20,6 +23,7 @@ module Cask end end + sig { void } def run outdated_casks = casks(alternative: -> { Caskroom.casks(config: Config.from_args(args)) }).select do |cask| odebug "Checking update info of Cask #{cask}" diff --git a/Library/Homebrew/cask/cmd/reinstall.rb b/Library/Homebrew/cask/cmd/reinstall.rb index 79e0dccc44..5d0af86177 100644 --- a/Library/Homebrew/cask/cmd/reinstall.rb +++ b/Library/Homebrew/cask/cmd/reinstall.rb @@ -7,10 +7,14 @@ module Cask # # @api private class Reinstall < Install + extend T::Sig + + sig { returns(String) } def self.description "Reinstalls the given ." end + sig { void } def run self.class.reinstall_casks( *casks, diff --git a/Library/Homebrew/cask/cmd/style.rb b/Library/Homebrew/cask/cmd/style.rb index 1d07156306..f0f1c34995 100644 --- a/Library/Homebrew/cask/cmd/style.rb +++ b/Library/Homebrew/cask/cmd/style.rb @@ -10,6 +10,9 @@ module Cask # # @api private class Style < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.description "Checks style of the given using RuboCop." end @@ -21,6 +24,7 @@ module Cask end end + sig { void } def run success = Homebrew::Style.check_style_and_print( cask_paths, diff --git a/Library/Homebrew/cask/cmd/uninstall.rb b/Library/Homebrew/cask/cmd/uninstall.rb index 8011193348..4fd6ac8980 100644 --- a/Library/Homebrew/cask/cmd/uninstall.rb +++ b/Library/Homebrew/cask/cmd/uninstall.rb @@ -7,10 +7,14 @@ module Cask # # @api private class Uninstall < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { returns(String) } def self.description "Uninstalls the given ." end @@ -23,6 +27,7 @@ module Cask end end + sig { void } def run self.class.uninstall_casks( *casks, diff --git a/Library/Homebrew/cask/cmd/upgrade.rb b/Library/Homebrew/cask/cmd/upgrade.rb index 56bcbd529c..28bc7b6a55 100644 --- a/Library/Homebrew/cask/cmd/upgrade.rb +++ b/Library/Homebrew/cask/cmd/upgrade.rb @@ -10,6 +10,9 @@ module Cask # # @api private class Upgrade < AbstractCommand + extend T::Sig + + sig { returns(String) } def self.description "Upgrades all outdated casks or the specified casks." end @@ -23,6 +26,7 @@ module Cask }], ].freeze + sig { returns(Homebrew::CLI::Parser) } def self.parser super do switch "--force", @@ -36,6 +40,7 @@ module Cask end end + sig { void } def run verbose = ($stdout.tty? || args.verbose?) && !args.quiet? self.class.upgrade_casks( @@ -52,6 +57,20 @@ module Cask ) 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( *casks, args:, @@ -81,7 +100,9 @@ module Cask 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" oh1 "#{verb} #{outdated_casks.count} #{"outdated package".pluralize(outdated_casks.count)}:" diff --git a/Library/Homebrew/cask/cmd/zap.rb b/Library/Homebrew/cask/cmd/zap.rb index 2898883ef6..d5b5dc3c80 100644 --- a/Library/Homebrew/cask/cmd/zap.rb +++ b/Library/Homebrew/cask/cmd/zap.rb @@ -7,10 +7,14 @@ module Cask # # @api private class Zap < AbstractCommand + extend T::Sig + + sig { override.returns(T.nilable(T.any(Integer, Symbol))) } def self.min_named :cask end + sig { returns(String) } def self.description <<~EOS Zaps all files associated with the given . Implicitly also performs all actions associated with `uninstall`. @@ -26,6 +30,7 @@ module Cask end end + sig { void } def run require "cask/installer" diff --git a/Library/Homebrew/cask/denylist.rb b/Library/Homebrew/cask/denylist.rb index 8cbc9c37a2..c6fd811c7d 100644 --- a/Library/Homebrew/cask/denylist.rb +++ b/Library/Homebrew/cask/denylist.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true module Cask @@ -6,6 +6,9 @@ module Cask # # @api private module Denylist + extend T::Sig + + sig { params(name: String).returns(T.nilable(String)) } def self.reason(name) case name when /^adobe-(after|illustrator|indesign|photoshop|premiere)/ diff --git a/Library/Homebrew/cask/dsl.rb b/Library/Homebrew/cask/dsl.rb index f0abafa93a..149fedb7de 100644 --- a/Library/Homebrew/cask/dsl.rb +++ b/Library/Homebrew/cask/dsl.rb @@ -125,7 +125,7 @@ module Cask def language(*args, default: false, &block) if args.empty? language_eval - elsif block_given? + elsif block @language_blocks ||= {} @language_blocks[args] = block @@ -248,7 +248,7 @@ module Cask def caveats(*strings, &block) @caveats ||= DSL::Caveats.new(cask) - if block_given? + if block @caveats.eval_caveats(&block) elsif strings.any? strings.each do |string| diff --git a/Library/Homebrew/cask/dsl/depends_on.rb b/Library/Homebrew/cask/dsl/depends_on.rb index 8e2280459a..8009749896 100644 --- a/Library/Homebrew/cask/dsl/depends_on.rb +++ b/Library/Homebrew/cask/dsl/depends_on.rb @@ -64,7 +64,7 @@ module Cask MacOSRequirement.new([version.to_sym], comparator: comparator) elsif /^\s*(?<|>|[=<>]=)\s*(?\S+)\s*$/ =~ args.first MacOSRequirement.new([version], comparator: comparator) - else + else # rubocop:disable Lint/DuplicateBranch MacOSRequirement.new([args.first], comparator: "==") end rescue MacOSVersionError => e diff --git a/Library/Homebrew/cask/dsl/version.rb b/Library/Homebrew/cask/dsl/version.rb index a43658b182..e2574db729 100644 --- a/Library/Homebrew/cask/dsl/version.rb +++ b/Library/Homebrew/cask/dsl/version.rb @@ -7,6 +7,8 @@ module Cask # # @api private class Version < ::String + extend T::Sig + DIVIDERS = { "." => :dots, "-" => :hyphens, @@ -62,6 +64,7 @@ module Cask attr_reader :raw_version + sig { params(raw_version: T.nilable(T.any(String, Symbol))).void } def initialize(raw_version) @raw_version = raw_version super(raw_version.to_s) @@ -73,6 +76,7 @@ module Cask raw_version.scan(INVALID_CHARACTERS) end + sig { returns(T::Boolean) } def unstable? return false if latest? @@ -84,6 +88,7 @@ module Cask false end + sig { returns(T::Boolean) } def latest? to_s == "latest" end @@ -134,6 +139,7 @@ module Cask private + sig { returns(T.self_type) } def version return self if empty? || latest? diff --git a/Library/Homebrew/cask/exceptions.rb b/Library/Homebrew/cask/exceptions.rb index 645ea8a0e4..b5576e9dee 100644 --- a/Library/Homebrew/cask/exceptions.rb +++ b/Library/Homebrew/cask/exceptions.rb @@ -11,12 +11,15 @@ module Cask # # @api private class MultipleCaskErrors < CaskError + extend T::Sig + def initialize(errors) super() @errors = errors end + sig { returns(String) } def to_s <<~EOS Problems with multiple casks: @@ -29,12 +32,18 @@ module Cask # # @api private 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) super() - @token = token + @token = token.to_s @reason = reason.to_s end end @@ -43,6 +52,9 @@ module Cask # # @api private class CaskNotInstalledError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s "Cask '#{token}' is not installed." end @@ -52,6 +64,8 @@ module Cask # # @api private class CaskConflictError < AbstractCaskErrorWithToken + extend T::Sig + attr_reader :conflicting_cask def initialize(token, conflicting_cask) @@ -59,6 +73,7 @@ module Cask @conflicting_cask = conflicting_cask end + sig { returns(String) } def to_s "Cask '#{token}' conflicts with '#{conflicting_cask}'." end @@ -68,6 +83,9 @@ module Cask # # @api private class CaskUnavailableError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s "Cask '#{token}' is unavailable#{reason.empty? ? "." : ": #{reason}"}" end @@ -77,6 +95,9 @@ module Cask # # @api private class CaskUnreadableError < CaskUnavailableError + extend T::Sig + + sig { returns(String) } def to_s "Cask '#{token}' is unreadable#{reason.empty? ? "." : ": #{reason}"}" end @@ -86,6 +107,9 @@ module Cask # # @api private class CaskAlreadyCreatedError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s %Q(Cask '#{token}' already exists. Run #{Formatter.identifier("brew cask edit #{token}")} to edit it.) end @@ -95,6 +119,9 @@ module Cask # # @api private class CaskAlreadyInstalledError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s <<~EOS Cask '#{token}' is already installed. @@ -109,6 +136,9 @@ module Cask # # @api private class CaskX11DependencyError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s <<~EOS Cask '#{token}' requires XQuartz/X11, which can be installed using Homebrew Cask by running: @@ -124,6 +154,9 @@ module Cask # # @api private class CaskCyclicDependencyError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s "Cask '#{token}' includes cyclic dependencies on other Casks#{reason.empty? ? "." : ": #{reason}"}" end @@ -133,6 +166,9 @@ module Cask # # @api private class CaskSelfReferencingDependencyError < CaskCyclicDependencyError + extend T::Sig + + sig { returns(String) } def to_s "Cask '#{token}' depends on itself." end @@ -142,6 +178,9 @@ module Cask # # @api private class CaskUnspecifiedError < CaskError + extend T::Sig + + sig { returns(String) } def to_s "This command requires a Cask token." end @@ -151,6 +190,9 @@ module Cask # # @api private class CaskInvalidError < AbstractCaskErrorWithToken + extend T::Sig + + sig { returns(String) } def to_s "Cask '#{token}' definition is invalid#{reason.empty? ? "." : ": #{reason}"}" end @@ -182,6 +224,9 @@ module Cask # # @api private class CaskSha256MissingError < CaskSha256Error + extend T::Sig + + sig { returns(String) } def to_s <<~EOS Cask '#{token}' requires a checksum: @@ -194,6 +239,8 @@ module Cask # # @api private class CaskSha256MismatchError < CaskSha256Error + extend T::Sig + attr_reader :path def initialize(token, expected, actual, path) @@ -201,6 +248,7 @@ module Cask @path = path end + sig { returns(String) } def to_s <<~EOS Checksum for Cask '#{token}' does not match. @@ -218,6 +266,9 @@ module Cask # # @api private class CaskNoShasumError < CaskSha256Error + extend T::Sig + + sig { returns(String) } def to_s <<~EOS Cask '#{token}' does not have a sha256 checksum defined and was not installed. @@ -230,6 +281,8 @@ module Cask # # @api private class CaskQuarantineError < CaskError + extend T::Sig + attr_reader :path, :reason def initialize(path, reason) @@ -239,6 +292,7 @@ module Cask @reason = reason end + sig { returns(String) } def to_s s = +"Failed to quarantine #{path}." @@ -256,6 +310,9 @@ module Cask # # @api private class CaskQuarantinePropagationError < CaskQuarantineError + extend T::Sig + + sig { returns(String) } def to_s s = +"Failed to quarantine one or more files within #{path}." @@ -273,6 +330,9 @@ module Cask # # @api private class CaskQuarantineReleaseError < CaskQuarantineError + extend T::Sig + + sig { returns(String) } def to_s s = +"Failed to release #{path} from quarantine." diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index f0310a1197..5c91866086 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -18,6 +18,8 @@ module Cask # # @api private class Installer + extend T::Sig + extend Predicable # TODO: it is unwise for Cask::Staged to be a module, when we are # 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 end + sig { returns(String) } def summary s = +"" s << "#{Homebrew::EnvConfig.install_badge} " unless Homebrew::EnvConfig.no_emoji? @@ -368,15 +371,19 @@ module Cask force: false, ).install else - FormulaInstaller.new(cask_or_formula, verbose: verbose?).yield_self do |fi| - fi.installed_as_dependency = true - fi.installed_on_request = false - fi.show_header = true - fi.prelude - fi.fetch - fi.install - fi.finish - end + fi = FormulaInstaller.new( + cask_or_formula, + **{ + show_header: true, + installed_as_dependency: true, + installed_on_request: false, + verbose: verbose?, + }.compact, + ) + fi.prelude + fi.fetch + fi.install + fi.finish end end end diff --git a/Library/Homebrew/cask/pkg.rb b/Library/Homebrew/cask/pkg.rb index b56f3ba194..b66ac90475 100644 --- a/Library/Homebrew/cask/pkg.rb +++ b/Library/Homebrew/cask/pkg.rb @@ -8,19 +8,25 @@ module Cask # # @api private class Pkg + extend T::Sig + + sig { params(regexp: String, command: T.class_of(SystemCommand)).returns(T::Array[Pkg]) } def self.all_matching(regexp, command) command.run("/usr/sbin/pkgutil", args: ["--pkgs=#{regexp}"]).stdout.split("\n").map do |package_id| new(package_id.chomp, command) end end + sig { returns(String) } attr_reader :package_id + sig { params(package_id: String, command: T.class_of(SystemCommand)).void } def initialize(package_id, command = SystemCommand) @package_id = package_id @command = command end + sig { void } def uninstall unless pkgutil_bom_files.empty? odebug "Deleting pkg files" @@ -65,23 +71,28 @@ module Cask forget end + sig { void } def forget odebug "Unregistering pkg receipt (aka forgetting)" @command.run!("/usr/sbin/pkgutil", args: ["--forget", package_id], sudo: true) end + sig { returns(T::Array[Pathname]) } def pkgutil_bom_files @pkgutil_bom_files ||= pkgutil_bom_all.select(&:file?) - pkgutil_bom_specials end + sig { returns(T::Array[Pathname]) } def pkgutil_bom_specials @pkgutil_bom_specials ||= pkgutil_bom_all.select(&method(:special?)) end + sig { returns(T::Array[Pathname]) } def pkgutil_bom_dirs @pkgutil_bom_dirs ||= pkgutil_bom_all.select(&:directory?) - pkgutil_bom_specials end + sig { returns(T::Array[Pathname]) } def pkgutil_bom_all @pkgutil_bom_all ||= @command.run!("/usr/sbin/pkgutil", args: ["--files", package_id]) .stdout @@ -90,6 +101,7 @@ module Cask .reject(&MacOS.public_method(:undeletable?)) end + sig { returns(Pathname) } def root @root ||= Pathname.new(info.fetch("volume")).join(info.fetch("install-location")) end @@ -101,10 +113,12 @@ module Cask private + sig { params(path: Pathname).returns(T::Boolean) } def special?(path) path.symlink? || path.chardev? || path.blockdev? end + sig { params(path: Pathname).void } def rmdir(path) return unless path.children.empty? @@ -115,7 +129,8 @@ module Cask 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_flags = @command.run!("/usr/bin/stat", args: ["-f", "%Of", "--", path]).stdout.chomp @@ -128,10 +143,12 @@ module Cask end end + sig { params(paths: T::Array[Pathname]).returns(T::Array[Pathname]) } def deepest_path_first(paths) paths.sort_by { |path| -path.to_s.split(File::SEPARATOR).count } end + sig { params(dir: Pathname).void } def clean_ds_store(dir) 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 # attempting to `rmdir` to prevent extra cruft from accumulating. + sig { params(dir: Pathname).void } def clean_broken_symlinks(dir) dir.children.select(&method(:broken_symlink?)).each do |path| @command.run!("/bin/rm", args: ["--", path], sudo: true) end end + sig { params(path: Pathname).returns(T::Boolean) } def broken_symlink?(path) path.symlink? && !path.exist? end diff --git a/Library/Homebrew/cask/quarantine.rb b/Library/Homebrew/cask/quarantine.rb index 14e74c7af0..de24b35d33 100644 --- a/Library/Homebrew/cask/quarantine.rb +++ b/Library/Homebrew/cask/quarantine.rb @@ -9,6 +9,8 @@ module Cask # # @api private module Quarantine + extend T::Sig + module_function QUARANTINE_ATTRIBUTE = "com.apple.quarantine" @@ -25,6 +27,7 @@ module Cask end private :xattr + sig { returns(Symbol) } def check_quarantine_support odebug "Checking quarantine support" diff --git a/Library/Homebrew/cask/staged.rb b/Library/Homebrew/cask/staged.rb index 76dd66323e..6069aef6b7 100644 --- a/Library/Homebrew/cask/staged.rb +++ b/Library/Homebrew/cask/staged.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "utils/user" @@ -8,25 +8,35 @@ module Cask # # @api private 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) full_paths = remove_nonexistent(paths) 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) 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) return if full_paths.empty? 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) end private + sig { params(paths: Paths).returns(T::Array[Pathname]) } def remove_nonexistent(paths) Array(paths).map { |p| Pathname(p).expand_path }.select(&:exist?) end diff --git a/Library/Homebrew/cask/staged.rbi b/Library/Homebrew/cask/staged.rbi new file mode 100644 index 0000000000..ddf5f8cdbc --- /dev/null +++ b/Library/Homebrew/cask/staged.rbi @@ -0,0 +1,7 @@ +# typed: strict + +module Cask + module Staged + include Kernel + end +end diff --git a/Library/Homebrew/cask/topological_hash.rb b/Library/Homebrew/cask/topological_hash.rb index 79c0485bf4..12b6f588e7 100644 --- a/Library/Homebrew/cask/topological_hash.rb +++ b/Library/Homebrew/cask/topological_hash.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "tsort" @@ -8,7 +8,11 @@ module Cask class TopologicalHash < Hash include TSort - alias tsort_each_node each_key + private + + def tsort_each_node(&block) + each_key(&block) + end def tsort_each_child(node, &block) fetch(node).each(&block) diff --git a/Library/Homebrew/cask/utils.rb b/Library/Homebrew/cask/utils.rb index 47f804df23..c9e831aebe 100644 --- a/Library/Homebrew/cask/utils.rb +++ b/Library/Homebrew/cask/utils.rb @@ -13,6 +13,8 @@ module Cask # # @api private module Utils + extend T::Sig + def self.gain_permissions_remove(path, command: SystemCommand) if path.respond_to?(:rmtree) && path.exist? gain_permissions(path, ["-R"], command) do |p| @@ -72,10 +74,12 @@ module Cask end end + sig { params(path: Pathname).returns(T::Boolean) } def self.path_occupied?(path) - File.exist?(path) || File.symlink?(path) + path.exist? || path.symlink? end + sig { returns(String) } def self.error_message_with_suggestions <<~EOS Follow the instructions here: diff --git a/Library/Homebrew/cleaner.rb b/Library/Homebrew/cleaner.rb index 070f5cb213..6acc77f1a9 100644 --- a/Library/Homebrew/cleaner.rb +++ b/Library/Homebrew/cleaner.rb @@ -76,6 +76,12 @@ class Cleaner path.text_executable? || path.executable? 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 # permissions and removing .la files, unless the files (or parent # directories) are protected by skip_clean. @@ -93,18 +99,10 @@ class Cleaner next if path.directory? - if path.extname == ".la" + if path.extname == ".la" || PERL_BASENAMES.include?(path.basename.to_s) path.unlink elsif path.symlink? # 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 # Set permissions for executables and non-executables perms = if executable_path?(path) diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb index a421715c35..3eac30a117 100644 --- a/Library/Homebrew/cleanup.rb +++ b/Library/Homebrew/cleanup.rb @@ -168,6 +168,7 @@ module Homebrew return false if Homebrew::EnvConfig.no_install_cleanup? unless PERIODIC_CLEAN_FILE.exist? + HOMEBREW_CACHE.mkpath FileUtils.touch PERIODIC_CLEAN_FILE return false end diff --git a/Library/Homebrew/cli/args.rb b/Library/Homebrew/cli/args.rb index 1a779dcbdf..b12f32712b 100644 --- a/Library/Homebrew/cli/args.rb +++ b/Library/Homebrew/cli/args.rb @@ -7,11 +7,14 @@ require "ostruct" module Homebrew module CLI class Args < OpenStruct + extend T::Sig + attr_reader :options_only, :flags_only # undefine tap to allow --tap argument undef tap + sig { void } def initialize super() @@ -21,7 +24,7 @@ module Homebrew # Can set these because they will be overwritten by freeze_named_args! # (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] = [] end @@ -30,7 +33,7 @@ module Homebrew end def freeze_named_args!(named_args) - self[:named_args] = NamedArgs.new( + self[:named] = NamedArgs.new( *named_args.freeze, override_spec: spec(nil), force_bottle: force_bottle?, @@ -50,8 +53,9 @@ module Homebrew @flags_only = cli_args.select { |a| a.start_with?("--") }.freeze end + sig { returns(NamedArgs) } def named - named_args + self[:named] end def no_named? @@ -131,6 +135,7 @@ module Homebrew flag_with_value.delete_prefix(arg_prefix) end + sig { returns(Context::ContextStruct) } def context Context::ContextStruct.new(debug: debug?, quiet: quiet?, verbose: verbose?) end diff --git a/Library/Homebrew/cli/args.rbi b/Library/Homebrew/cli/args.rbi index 2314e9c8f3..b072016115 100644 --- a/Library/Homebrew/cli/args.rbi +++ b/Library/Homebrew/cli/args.rbi @@ -3,27 +3,62 @@ module Homebrew module CLI class Args < OpenStruct + sig { returns(T.nilable(T::Boolean)) } def devel?; end + sig { returns(T.nilable(T::Boolean)) } def HEAD?; end + sig { returns(T.nilable(T::Boolean)) } def include_test?; end + sig { returns(T.nilable(T::Boolean)) } def build_bottle?; end + sig { returns(T.nilable(T::Boolean)) } def build_universal?; end + sig { returns(T.nilable(T::Boolean)) } def build_from_source?; end - def named_args; end - + sig { returns(T.nilable(T::Boolean)) } def force_bottle?; end + sig { returns(T.nilable(T::Boolean)) } def debug?; end + sig { returns(T.nilable(T::Boolean)) } def quiet?; end + sig { returns(T.nilable(T::Boolean)) } 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 diff --git a/Library/Homebrew/cli/named_args.rb b/Library/Homebrew/cli/named_args.rb index 99ef08e341..f827bc070f 100644 --- a/Library/Homebrew/cli/named_args.rb +++ b/Library/Homebrew/cli/named_args.rb @@ -6,6 +6,7 @@ require "delegate" require "cask/cask_loader" require "cli/args" require "formulary" +require "keg" require "missing_formula" module Homebrew @@ -13,7 +14,9 @@ module Homebrew # Helper class for loading formulae/casks from named arguments. # # @api private - class NamedArgs < SimpleDelegator + class NamedArgs < Array + extend T::Sig + def initialize(*args, parent: Args.new, override_spec: nil, force_bottle: false, flags: []) @args = args @override_spec = override_spec @@ -39,9 +42,9 @@ module Homebrew 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[[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) } .map(&:freeze).freeze end @@ -62,14 +65,16 @@ module Homebrew when nil, :factory Formulary.factory(name, *spec, force_bottle: @force_bottle, flags: @flags) when :resolve - Formulary.resolve(name, spec: spec, force_bottle: @force_bottle, flags: @flags) + resolve_formula(name) + when :keg + resolve_keg(name) else raise end warn_if_cask_conflicts(name, "formula") unless only == :formula return formula - rescue FormulaUnavailableError => e + rescue NoSuchKegError, FormulaUnavailableError => e raise e if only == :formula end end @@ -97,24 +102,22 @@ module Homebrew end 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 - # 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 # formula and prints a warning unless `only` is specified. def to_objects(only: nil, method: nil) @to_objects ||= {} - @to_objects[only] ||= downcased_unique_named.flat_map do |name| - next Tap.fetch(name) if only == :tap || (only.nil? && name.count("/") == 1 && !name.start_with?("./", "/")) - + @to_objects[only] ||= downcased_unique_named.map do |name| load_formula_or_cask(name, only: only, method: method) end.uniq.freeze end private :to_objects def to_formulae_paths - to_paths(only: :formulae) + to_paths(only: :formula) end # 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| if File.exist?(name) Pathname(name) - elsif name.count("/") == 1 + elsif name.count("/") == 1 && !name.start_with?("./", "/") Tap.fetch(name).path else - next Formulary.path(name) if only == :formulae - next Cask::CaskLoader.path(name) if only == :casks + next Formulary.path(name) if only == :formula + next Cask::CaskLoader.path(name) if only == :cask formula_path = Formulary.path(name) cask_path = Cask::CaskLoader.path(name) @@ -144,44 +147,33 @@ module Homebrew end.uniq.freeze end + sig { returns(T::Array[Keg]) } def to_kegs - @to_kegs ||= downcased_unique_named.map do |name| - resolve_keg name + @to_kegs ||= begin + to_formulae_and_casks(only: :formula, method: :keg).freeze rescue NoSuchKegError => e - if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall")) + if (reason = Homebrew::MissingFormula.suggest_command(e.name, "uninstall")) $stderr.puts reason end 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 + 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 downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX) end private + sig { returns(T::Array[String]) } def downcased_unique_named # Only lowercase names, not paths, bottle filenames or URLs map do |arg| diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index f9653219f7..331bc71416 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -14,6 +14,8 @@ OPTION_DESC_WIDTH = 43 module Homebrew module CLI class Parser + extend T::Sig + attr_reader :processed_options, :hide_from_man_page def self.from_cmd_path(cmd_path) @@ -31,78 +33,82 @@ module Homebrew def self.global_cask_options [ [:flag, "--appdir=", { - description: "Target location for Applications. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:appdir]}`", + description: "Target location for Applications " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:appdir]}`).", }], [:flag, "--colorpickerdir=", { - description: "Target location for Color Pickers. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:colorpickerdir]}`", + description: "Target location for Color Pickers " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:colorpickerdir]}`).", }], [:flag, "--prefpanedir=", { - description: "Target location for Preference Panes. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:prefpanedir]}`", + description: "Target location for Preference Panes " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:prefpanedir]}`).", }], [:flag, "--qlplugindir=", { - description: "Target location for QuickLook Plugins. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:qlplugindir]}`", + description: "Target location for QuickLook Plugins " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:qlplugindir]}`).", }], [:flag, "--mdimporterdir=", { - description: "Target location for Spotlight Plugins. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:mdimporterdir]}`", + description: "Target location for Spotlight Plugins " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:mdimporterdir]}`).", }], [:flag, "--dictionarydir=", { - description: "Target location for Dictionaries. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:dictionarydir]}`", + description: "Target location for Dictionaries " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:dictionarydir]}`).", }], [:flag, "--fontdir=", { - description: "Target location for Fonts. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:fontdir]}`", + description: "Target location for Fonts " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:fontdir]}`).", }], [:flag, "--servicedir=", { - description: "Target location for Services. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:servicedir]}`", + description: "Target location for Services " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:servicedir]}`).", }], [:flag, "--input_methoddir=", { - description: "Target location for Input Methods. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:input_methoddir]}`", + description: "Target location for Input Methods " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:input_methoddir]}`).", }], [:flag, "--internet_plugindir=", { - description: "Target location for Internet Plugins. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:internet_plugindir]}`", + description: "Target location for Internet Plugins " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:internet_plugindir]}`).", }], [:flag, "--audio_unit_plugindir=", { - description: "Target location for Audio Unit Plugins. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:audio_unit_plugindir]}`", + description: "Target location for Audio Unit Plugins " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:audio_unit_plugindir]}`).", }], [:flag, "--vst_plugindir=", { - description: "Target location for VST Plugins. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:vst_plugindir]}`", + description: "Target location for VST Plugins " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:vst_plugindir]}`).", }], [:flag, "--vst3_plugindir=", { - description: "Target location for VST3 Plugins. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:vst3_plugindir]}`", + description: "Target location for VST3 Plugins " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:vst3_plugindir]}`).", }], [:flag, "--screen_saverdir=", { - description: "Target location for Screen Savers. " \ - "Default: `#{Cask::Config::DEFAULT_DIRS[:screen_saverdir]}`", + description: "Target location for Screen Savers " \ + "(default: `#{Cask::Config::DEFAULT_DIRS[:screen_saverdir]}`).", }], [:comma_array, "--language", { - description: "Set language of the Cask to install. The first matching " \ - "language is used, otherwise the default language on the Cask. " \ - "The default value is the `language of your system`", + description: "Comma-separated list of language codes to prefer for cask installation. " \ + "The first matching language is used, otherwise it reverts to the cask's " \ + "default language. The default value is the language of your system.", }], ] end + sig { returns(T::Array[[String, String, String]]) } def self.global_options [ ["-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."], ["-h", "--help", "Show this message."], ] 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) @parser = OptionParser.new @@ -130,7 +136,7 @@ module Homebrew switch short, long, description: desc, env: option_to_name(long), method: :on_tail end - instance_eval(&block) if block_given? + instance_eval(&block) if block end 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 @parser.banner - .gsub(/^ - (`[^`]+`)\s+/, "\n- \\1 \n ") # Format `cask` subcommands as MarkDown list. + .gsub(/^ - (`[^`]+`)\s+/, "\n- \\1:\n
") # Format `cask` subcommands as Markdown list. end def comma_array(name, description: nil) @@ -331,6 +337,7 @@ module Homebrew end end + sig { void } def formula_options @formula_options = true end @@ -367,6 +374,7 @@ module Homebrew end end + sig { void } def hide_from_man_page! @hide_from_man_page = true end @@ -454,20 +462,24 @@ module Homebrew end def check_named_args(args) - min_exception = case @min_named_type - when :cask - Cask::CaskUnspecifiedError - when :formula - FormulaUnspecifiedError - when :formula_or_cask - FormulaOrCaskUnspecifiedError - when :keg - KegUnspecifiedError - else - MinNamedArgumentsError.new(@min_named_args) + exception = if @min_named_args && args.size < @min_named_args + case @min_named_type + when :cask + Cask::CaskUnspecifiedError + when :formula + FormulaUnspecifiedError + when :formula_or_cask + FormulaOrCaskUnspecifiedError + when :keg + KegUnspecifiedError + else + MinNamedArgumentsError.new(@min_named_args) + end + elsif @max_named_args && args.size > @max_named_args + MaxNamedArgumentsError.new(@max_named_args) 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 def process_option(*args) @@ -535,6 +547,9 @@ module Homebrew end class MaxNamedArgumentsError < UsageError + extend T::Sig + + sig { params(maximum: Integer).void } def initialize(maximum) super case maximum when 0 @@ -546,6 +561,9 @@ module Homebrew end class MinNamedArgumentsError < UsageError + extend T::Sig + + sig { params(minimum: Integer).void } def initialize(minimum) super "This command requires at least #{minimum} named #{"argument".pluralize(minimum)}." end diff --git a/Library/Homebrew/cmd/--cache.rb b/Library/Homebrew/cmd/--cache.rb index 3a52708065..d21f3bd8cd 100644 --- a/Library/Homebrew/cmd/--cache.rb +++ b/Library/Homebrew/cmd/--cache.rb @@ -6,14 +6,17 @@ require "cli/parser" require "cask/download" module Homebrew + extend T::Sig + extend Fetch module_function + sig { returns(CLI::Parser) } def __cache_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `--cache` [] [] + `--cache` [] [|] Display Homebrew's download cache. See also `HOMEBREW_CACHE`. diff --git a/Library/Homebrew/cmd/--caskroom.rb b/Library/Homebrew/cmd/--caskroom.rb index b53574fd0a..6facedc9c8 100644 --- a/Library/Homebrew/cmd/--caskroom.rb +++ b/Library/Homebrew/cmd/--caskroom.rb @@ -1,9 +1,12 @@ -# typed: false +# typed: strict # frozen_string_literal: true module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def __caskroom_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -17,6 +20,7 @@ module Homebrew end end + sig { void } def __caskroom args = __caskroom_args.parse diff --git a/Library/Homebrew/cmd/--env.rb b/Library/Homebrew/cmd/--env.rb index 45b609ca53..a7eec71143 100644 --- a/Library/Homebrew/cmd/--env.rb +++ b/Library/Homebrew/cmd/--env.rb @@ -7,8 +7,11 @@ require "utils/shell" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def __env_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -44,11 +47,10 @@ module Homebrew Utils::Shell.from_path(args.shell) end - env_keys = BuildEnvironment.keys(ENV) if shell.nil? BuildEnvironment.dump ENV else - env_keys.each do |key| + BuildEnvironment.keys(ENV).each do |key| puts Utils::Shell.export_value(key, ENV[key], shell) end end diff --git a/Library/Homebrew/cmd/--prefix.rb b/Library/Homebrew/cmd/--prefix.rb index b451a24f7b..42410ab30a 100644 --- a/Library/Homebrew/cmd/--prefix.rb +++ b/Library/Homebrew/cmd/--prefix.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def __prefix_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/--repository.rb b/Library/Homebrew/cmd/--repository.rb index 042c39b36d..c27c4589fd 100644 --- a/Library/Homebrew/cmd/--repository.rb +++ b/Library/Homebrew/cmd/--repository.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def __repository_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/--version.rb b/Library/Homebrew/cmd/--version.rb index 93595a9a3d..ff038f7096 100644 --- a/Library/Homebrew/cmd/--version.rb +++ b/Library/Homebrew/cmd/--version.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def __version_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -14,6 +17,7 @@ module Homebrew Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask (if tapped) to standard output. EOS + max_named 0 end end diff --git a/Library/Homebrew/cmd/analytics.rb b/Library/Homebrew/cmd/analytics.rb index 957b175b85..0efdf6afe1 100644 --- a/Library/Homebrew/cmd/analytics.rb +++ b/Library/Homebrew/cmd/analytics.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def analytics_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -17,12 +20,13 @@ module Homebrew `brew analytics` [`state`]: Display the current state of Homebrew's analytics. - `brew analytics` [`on`|`off`]: + `brew analytics` (`on`|`off`): Turn Homebrew's analytics on or off respectively. `brew analytics regenerate-uuid`: Regenerate the UUID used for Homebrew's analytics. EOS + max_named 1 end end diff --git a/Library/Homebrew/cmd/autoremove.rb b/Library/Homebrew/cmd/autoremove.rb index fd5c786f5b..21c211cfea 100644 --- a/Library/Homebrew/cmd/autoremove.rb +++ b/Library/Homebrew/cmd/autoremove.rb @@ -17,7 +17,8 @@ module Homebrew EOS switch "-n", "--dry-run", description: "List what would be uninstalled, but do not actually uninstall anything." - named 0 + + max_named 0 end end diff --git a/Library/Homebrew/cmd/cleanup.rb b/Library/Homebrew/cmd/cleanup.rb index c0294392d7..0c7ac6df81 100644 --- a/Library/Homebrew/cmd/cleanup.rb +++ b/Library/Homebrew/cmd/cleanup.rb @@ -5,8 +5,11 @@ require "cleanup" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def cleanup_args Homebrew::CLI::Parser.new do days = Homebrew::EnvConfig::ENVS[:HOMEBREW_CLEANUP_MAX_AGE_DAYS][:default] diff --git a/Library/Homebrew/cmd/commands.rb b/Library/Homebrew/cmd/commands.rb index cbcb36a495..92fed7e063 100644 --- a/Library/Homebrew/cmd/commands.rb +++ b/Library/Homebrew/cmd/commands.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def commands_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/config.rb b/Library/Homebrew/cmd/config.rb index 562d9a9f1c..970af3093a 100644 --- a/Library/Homebrew/cmd/config.rb +++ b/Library/Homebrew/cmd/config.rb @@ -5,8 +5,11 @@ require "system_config" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def config_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/deps.rb b/Library/Homebrew/cmd/deps.rb index a5f8ade23a..42e50c984a 100644 --- a/Library/Homebrew/cmd/deps.rb +++ b/Library/Homebrew/cmd/deps.rb @@ -8,10 +8,13 @@ require "cask/caskroom" require "dependencies_helpers" module Homebrew + extend T::Sig + extend DependenciesHelpers module_function + sig { returns(CLI::Parser) } def deps_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/desc.rb b/Library/Homebrew/cmd/desc.rb index e9616f1749..b2b0b8675e 100644 --- a/Library/Homebrew/cmd/desc.rb +++ b/Library/Homebrew/cmd/desc.rb @@ -7,10 +7,13 @@ require "description_cache_store" require "cli/parser" module Homebrew + extend T::Sig + module_function extend Search + sig { returns(CLI::Parser) } def desc_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/doctor.rb b/Library/Homebrew/cmd/doctor.rb index 5d10f9f655..5a3136f147 100644 --- a/Library/Homebrew/cmd/doctor.rb +++ b/Library/Homebrew/cmd/doctor.rb @@ -6,8 +6,11 @@ require "cli/parser" require "cask/caskroom" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def doctor_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb index 9baa5cec4e..ac03b5df07 100644 --- a/Library/Homebrew/cmd/fetch.rb +++ b/Library/Homebrew/cmd/fetch.rb @@ -6,10 +6,13 @@ require "fetch" require "cli/parser" module Homebrew + extend T::Sig + extend Fetch module_function + sig { returns(CLI::Parser) } def fetch_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index 7d3064c7e5..d590fb3526 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -9,10 +9,13 @@ require "socket" require "cli/parser" module Homebrew + extend T::Sig + extend Install module_function + sig { returns(CLI::Parser) } def gist_logs_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/home.rb b/Library/Homebrew/cmd/home.rb index 2c147bb6d6..2308392968 100644 --- a/Library/Homebrew/cmd/home.rb +++ b/Library/Homebrew/cmd/home.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def home_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index ae94558803..908642fcb8 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -13,12 +13,15 @@ require "utils/spdx" require "deprecate_disable" module Homebrew + extend T::Sig + module_function VALID_DAYS = %w[30 90 365].freeze VALID_FORMULA_CATEGORIES = %w[install install-on-request build-error].freeze VALID_CATEGORIES = (VALID_FORMULA_CATEGORIES + %w[cask-install os-version]).freeze + sig { returns(CLI::Parser) } def info_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -87,20 +90,23 @@ module Homebrew raise FormulaOrCaskUnspecifiedError if args.no_named? exec_browser(*args.named.to_formulae_and_casks.map { |f| github_info(f) }) + elsif args.no_named? + print_statistics else print_info(args: args) 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:) if args.no_named? - if args.analytics? - Utils::Analytics.output(args: args) - elsif HOMEBREW_CELLAR.exist? - count = Formula.racks.length - puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.dup.abv}" - end - + Utils::Analytics.output(args: args) return end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 3f72fa2b28..aa0bb63ac5 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -14,10 +14,13 @@ require "cli/parser" require "upgrade" module Homebrew + extend T::Sig + extend Search module_function + sig { returns(CLI::Parser) } def install_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -82,7 +85,6 @@ module Homebrew }], [:switch, "--keep-tmp", { description: "Retain the temporary files created during installation.", - }], [:switch, "--build-bottle", { description: "Prepare the formula for eventual bottling during installation, skipping any " \ @@ -122,7 +124,6 @@ module Homebrew conflicts "--ignore-dependencies", "--only-dependencies" conflicts "--build-from-source", "--build-bottle", "--force-bottle" - min_named :formula_or_cask end end @@ -203,7 +204,7 @@ module Homebrew EOS elsif args.only_dependencies? installed_formulae << f - else + elsif !args.quiet? opoo <<~EOS #{f.full_name} #{f.pkg_version} is already installed and up-to-date 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" linked_not_equals_installed = f.linked_version != installed_version if f.linked? && linked_not_equals_installed - msg = <<~EOS - #{msg} - The currently linked version is #{f.linked_version} - You can use `brew switch #{f} #{installed_version}` to link this version. - EOS + msg = if args.quiet? + nil + else + <<~EOS + #{msg} + The currently linked version is #{f.linked_version} + EOS + end elsif !f.linked? || f.keg_only? msg = <<~EOS #{msg}, it's just not linked @@ -237,10 +241,14 @@ module Homebrew msg = nil installed_formulae << f else - msg = <<~EOS - #{msg} and up-to-date - To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}` - EOS + msg = if args.quiet? + nil + else + <<~EOS + #{msg} and up-to-date + To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}` + EOS + end end opoo msg if msg elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first @@ -250,8 +258,10 @@ module Homebrew #{msg}, it's just not linked. You can use `brew link #{old_formula.full_name}` to link this version. EOS + elsif args.quiet? + msg = nil end - opoo msg + opoo msg if msg elsif f.migration_needed? && !args.force? # Check if the formula we try to install is the same as installed # but not migrated one. If --force is passed then install anyway. @@ -288,7 +298,7 @@ module Homebrew Cleanup.install_formula_clean!(f) end - Upgrade.check_installed_dependents(args: args) + Upgrade.check_installed_dependents(installed_formulae, args: args) Homebrew.messages.display_messages(display_times: args.display_times?) rescue FormulaUnreadableError, FormulaClassUnavailableError, @@ -347,21 +357,28 @@ module Homebrew f.print_tap_action build_options = f.build - fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?, - include_test_formulae: args.include_test_formulae, - build_from_source_formulae: args.build_from_source_formulae, - debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?) - fi.options = build_options.used_options - fi.env = args.env - fi.force = args.force? - fi.keep_tmp = args.keep_tmp? - fi.ignore_deps = args.ignore_dependencies? - fi.only_deps = args.only_dependencies? - fi.build_bottle = args.build_bottle? - fi.bottle_arch = args.bottle_arch - fi.interactive = args.interactive? - fi.git = args.git? - fi.cc = args.cc + fi = FormulaInstaller.new( + f, + **{ + options: build_options.used_options, + build_bottle: args.build_bottle?, + force_bottle: args.force_bottle?, + bottle_arch: args.bottle_arch, + ignore_deps: args.ignore_dependencies?, + only_deps: args.only_dependencies?, + include_test_formulae: args.include_test_formulae, + build_from_source_formulae: args.build_from_source_formulae, + env: args.env, + cc: args.cc, + git: args.git?, + interactive: args.interactive?, + keep_tmp: args.keep_tmp?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose?, + }.compact, + ) fi.prelude fi.fetch fi.install diff --git a/Library/Homebrew/cmd/leaves.rb b/Library/Homebrew/cmd/leaves.rb index 7cb1497367..f4c2c471a7 100644 --- a/Library/Homebrew/cmd/leaves.rb +++ b/Library/Homebrew/cmd/leaves.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def leaves_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/link.rb b/Library/Homebrew/cmd/link.rb index 6666f5576d..98a265d610 100644 --- a/Library/Homebrew/cmd/link.rb +++ b/Library/Homebrew/cmd/link.rb @@ -7,8 +7,11 @@ require "cli/parser" require "unlink" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def link_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/list.rb b/Library/Homebrew/cmd/list.rb index 8fe034844e..e7e5a97536 100644 --- a/Library/Homebrew/cmd/list.rb +++ b/Library/Homebrew/cmd/list.rb @@ -7,19 +7,22 @@ require "cli/parser" require "cask/cmd" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def list_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `list`, `ls` [] [] + `list`, `ls` [] [|] - List all installed formulae or casks + List all installed formulae and casks. If is provided, summarise the paths within its current keg. EOS 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", description: "List only casks, or if provided." switch "--unbrewed", diff --git a/Library/Homebrew/cmd/log.rb b/Library/Homebrew/cmd/log.rb index f2d8b1c4e1..391d213f52 100644 --- a/Library/Homebrew/cmd/log.rb +++ b/Library/Homebrew/cmd/log.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def log_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -25,8 +28,9 @@ module Homebrew description: "Print only one commit." flag "-n", "--max-count=", description: "Print only a specified number of commits." - max_named 1 + conflicts "-1", "--max-count" + max_named 1 end end diff --git a/Library/Homebrew/cmd/migrate.rb b/Library/Homebrew/cmd/migrate.rb index f400036c78..b5bf51a008 100644 --- a/Library/Homebrew/cmd/migrate.rb +++ b/Library/Homebrew/cmd/migrate.rb @@ -5,8 +5,11 @@ require "migrator" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def migrate_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/missing.rb b/Library/Homebrew/cmd/missing.rb index 4345227585..4ab86a49fc 100644 --- a/Library/Homebrew/cmd/missing.rb +++ b/Library/Homebrew/cmd/missing.rb @@ -7,8 +7,11 @@ require "diagnostic" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def missing_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/options.rb b/Library/Homebrew/cmd/options.rb index 6ecc3c7fc9..b94c0aa6f3 100644 --- a/Library/Homebrew/cmd/options.rb +++ b/Library/Homebrew/cmd/options.rb @@ -7,8 +7,11 @@ require "cli/parser" require "commands" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def options_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb index 623f434729..6cb52621cb 100644 --- a/Library/Homebrew/cmd/outdated.rb +++ b/Library/Homebrew/cmd/outdated.rb @@ -8,8 +8,11 @@ require "cask/cmd" require "cask/caskroom" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def outdated_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -23,9 +26,9 @@ module Homebrew switch "-v", "--verbose", description: "Include detailed version information." switch "--formula", - description: "Only output outdated formulae." + description: "List only outdated formulae." switch "--cask", - description: "Only output outdated casks." + description: "List only outdated casks." flag "--json", 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. " \ diff --git a/Library/Homebrew/cmd/pin.rb b/Library/Homebrew/cmd/pin.rb index 0ca4458d92..b777ac3b5f 100644 --- a/Library/Homebrew/cmd/pin.rb +++ b/Library/Homebrew/cmd/pin.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def pin_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/postinstall.rb b/Library/Homebrew/cmd/postinstall.rb index 1b4885a36a..ce7113833d 100644 --- a/Library/Homebrew/cmd/postinstall.rb +++ b/Library/Homebrew/cmd/postinstall.rb @@ -6,8 +6,11 @@ require "formula_installer" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def postinstall_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -25,7 +28,7 @@ module Homebrew args.named.to_resolved_formulae.each do |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 end end diff --git a/Library/Homebrew/cmd/readall.rb b/Library/Homebrew/cmd/readall.rb index 5bfa660543..7a2361036c 100644 --- a/Library/Homebrew/cmd/readall.rb +++ b/Library/Homebrew/cmd/readall.rb @@ -5,8 +5,11 @@ require "readall" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def readall_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb index 93e4c12936..7c58fb9c2b 100644 --- a/Library/Homebrew/cmd/reinstall.rb +++ b/Library/Homebrew/cmd/reinstall.rb @@ -14,8 +14,11 @@ require "cask/macos" require "upgrade" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def reinstall_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -42,8 +45,8 @@ module Homebrew }], [:switch, "-i", "--interactive", { description: "Download and patch , then open a shell. This allows the user to " \ - "run `./configure --help` and otherwise determine how to turn the software " \ - "package into a Homebrew package.", + "run `./configure --help` and otherwise determine how to turn the software " \ + "package into a Homebrew package.", }], [:switch, "--force-bottle", { description: "Install from a bottle if it exists for the current or newest version of " \ @@ -72,7 +75,6 @@ module Homebrew cask_options conflicts "--build-from-source", "--force-bottle" - min_named :formula_or_cask end end @@ -100,7 +102,7 @@ module Homebrew Cleanup.install_formula_clean!(f) end - Upgrade.check_installed_dependents(args: args) + Upgrade.check_installed_dependents(formulae, args: args) if casks.any? Cask::Cmd::Reinstall.reinstall_casks( diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index beaa14edad..4dca6423bb 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -8,6 +8,8 @@ require "cli/parser" require "search" module Homebrew + extend T::Sig + module_function extend Search @@ -25,6 +27,7 @@ module Homebrew }, }.freeze + sig { returns(CLI::Parser) } def search_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -47,7 +50,7 @@ module Homebrew description: "Search for formulae with a description matching and casks with "\ "a name matching ." switch "--pull-request", - description: "Search for GitHub pull requests for ." + description: "Search for GitHub pull requests containing ." package_manager_switches = PACKAGE_MANAGERS.keys.map { |name| "--#{name}" } package_manager_switches.each do |s| diff --git a/Library/Homebrew/cmd/switch.rb b/Library/Homebrew/cmd/switch.rb index 0877f51d09..a78ef0a907 100644 --- a/Library/Homebrew/cmd/switch.rb +++ b/Library/Homebrew/cmd/switch.rb @@ -6,8 +6,11 @@ require "keg" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def switch_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/tap-info.rb b/Library/Homebrew/cmd/tap-info.rb index 6c01e4172a..81284e8c0d 100644 --- a/Library/Homebrew/cmd/tap-info.rb +++ b/Library/Homebrew/cmd/tap-info.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def tap_info_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/tap.rb b/Library/Homebrew/cmd/tap.rb index df6f428ff1..86e7a0fc1b 100644 --- a/Library/Homebrew/cmd/tap.rb +++ b/Library/Homebrew/cmd/tap.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def tap_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb index 2fadf91c50..7b787d923e 100644 --- a/Library/Homebrew/cmd/uninstall.rb +++ b/Library/Homebrew/cmd/uninstall.rb @@ -11,8 +11,11 @@ require "cask/cask_loader" require "uninstall" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def uninstall_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -26,6 +29,12 @@ module Homebrew description: "Don't fail uninstall, even if is a dependency of any installed "\ "formulae." + switch "--formula", "--formulae", + description: "Treat all named arguments as formulae." + switch "--cask", "--casks", + description: "Treat all named arguments as casks." + conflicts "--formula", "--cask" + min_named :formula end end @@ -33,25 +42,29 @@ module Homebrew def uninstall args = uninstall_args.parse + only = :formula if args.formula? && !args.cask? + only = :cask if args.cask? && !args.formula? + if args.force? casks = [] kegs_by_rack = {} args.named.each do |name| - rack = Formulary.to_rack(name) + if only != :cask + rack = Formulary.to_rack(name) + kegs_by_rack[rack] = rack.subdirs.map { |d| Keg.new(d) } if rack.directory? + end - if rack.directory? - kegs_by_rack[rack] = rack.subdirs.map { |d| Keg.new(d) } - else - begin - casks << Cask::CaskLoader.load(name) - rescue Cask::CaskUnavailableError - # Since the uninstall was forced, ignore any unavailable casks - end + next if only == :formula + + begin + casks << Cask::CaskLoader.load(name) + rescue Cask::CaskUnavailableError + # Since the uninstall was forced, ignore any unavailable casks. end end else - all_kegs, casks = args.named.to_kegs_to_casks + all_kegs, casks = args.named.to_kegs_to_casks(only: only) kegs_by_rack = all_kegs.group_by(&:rack) end diff --git a/Library/Homebrew/cmd/unlink.rb b/Library/Homebrew/cmd/unlink.rb index 2abbc3d947..1036b8eaf9 100644 --- a/Library/Homebrew/cmd/unlink.rb +++ b/Library/Homebrew/cmd/unlink.rb @@ -6,8 +6,11 @@ require "cli/parser" require "unlink" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def unlink_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/unpin.rb b/Library/Homebrew/cmd/unpin.rb index 77bf7b1576..1f650adae1 100644 --- a/Library/Homebrew/cmd/unpin.rb +++ b/Library/Homebrew/cmd/unpin.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def unpin_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/untap.rb b/Library/Homebrew/cmd/untap.rb index b8f6a93016..d3e70e7e5e 100644 --- a/Library/Homebrew/cmd/untap.rb +++ b/Library/Homebrew/cmd/untap.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def untap_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index b4efd2d7f5..24406a4764 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -10,6 +10,8 @@ require "description_cache_store" require "cli/parser" module Homebrew + extend T::Sig + module_function def update_preinstall_header(args:) @@ -19,6 +21,7 @@ module Homebrew end end + sig { returns(CLI::Parser) } def update_report_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -413,10 +416,13 @@ class Reporter end class ReporterHub + extend T::Sig + extend Forwardable attr_reader :reporters + sig { void } def initialize @hash = {} @reporters = [] diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index b7a53cbd40..ae0f3ba280 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -10,8 +10,11 @@ require "cask/utils" require "cask/macos" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def upgrade_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -44,8 +47,8 @@ module Homebrew }], [:switch, "-i", "--interactive", { description: "Download and patch , then open a shell. This allows the user to "\ - "run `./configure --help` and otherwise determine how to turn the software "\ - "package into a Homebrew package.", + "run `./configure --help` and otherwise determine how to turn the software "\ + "package into a Homebrew package.", }], [:switch, "--force-bottle", { description: "Install from a bottle if it exists for the current or newest version of "\ @@ -55,7 +58,6 @@ module Homebrew description: "Fetch the upstream repository to detect if the HEAD installation of the "\ "formula is outdated. Otherwise, the repository's HEAD will only be checked for "\ "updates when a new stable or development version has been released.", - }], [:switch, "--ignore-pinned", { description: "Set a successful exit status even if pinned formulae are not upgraded.", @@ -89,6 +91,7 @@ module Homebrew end end + sig { void } def upgrade args = upgrade_args.parse @@ -106,6 +109,7 @@ module Homebrew upgrade_outdated_casks(casks, args: args) unless upgrade_formulae end + sig { params(formulae: T::Array[Formula], args: CLI::Args).void } def upgrade_outdated_formulae(formulae, args:) return if args.cask? @@ -168,11 +172,12 @@ module Homebrew Upgrade.upgrade_formulae(formulae_to_install, args: args) - Upgrade.check_installed_dependents(args: args) + Upgrade.check_installed_dependents(formulae_to_install, args: args) Homebrew.messages.display_messages(display_times: args.display_times?) end + sig { params(casks: T::Array[Cask::Cask], args: CLI::Args).void } def upgrade_outdated_casks(casks, args:) return if args.formula? diff --git a/Library/Homebrew/cmd/uses.rb b/Library/Homebrew/cmd/uses.rb index 8b2f912436..1b0ef16e8c 100644 --- a/Library/Homebrew/cmd/uses.rb +++ b/Library/Homebrew/cmd/uses.rb @@ -11,10 +11,13 @@ require "cask/caskroom" require "dependencies_helpers" module Homebrew + extend T::Sig + extend DependenciesHelpers module_function + sig { returns(CLI::Parser) } def uses_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -37,6 +40,7 @@ module Homebrew description: "Include all formulae that specify as `:optional` type dependency." switch "--skip-recommended", description: "Skip all formulae that specify as `:recommended` type dependency." + min_named :formula end end diff --git a/Library/Homebrew/compilers.rb b/Library/Homebrew/compilers.rb index c8a9dfe584..8881c84133 100644 --- a/Library/Homebrew/compilers.rb +++ b/Library/Homebrew/compilers.rb @@ -56,7 +56,7 @@ class CompilerFailure def initialize(name, version, &block) @name = name @version = Version.parse(version.to_s) - instance_eval(&block) if block_given? + instance_eval(&block) if block end def fails_with?(compiler) diff --git a/Library/Homebrew/config.rb b/Library/Homebrew/config.rb index feecc8373a..566be1eae6 100644 --- a/Library/Homebrew/config.rb +++ b/Library/Homebrew/config.rb @@ -4,28 +4,36 @@ raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!" unless ENV["HOMEBREW_BREW_FILE"] # Path to `bin/brew` main executable in `HOMEBREW_PREFIX` -HOMEBREW_BREW_FILE = Pathname.new(ENV["HOMEBREW_BREW_FILE"]).freeze +HOMEBREW_BREW_FILE = Pathname(ENV["HOMEBREW_BREW_FILE"]).freeze class MissingEnvironmentVariables < RuntimeError; end -def get_env_or_raise(env) - raise MissingEnvironmentVariables, "#{env} was not exported!" unless ENV[env] +# Helper module for getting environment variables which must be set. +# +# @api private +module EnvVar + extend T::Sig - ENV[env] + sig { params(env: String).returns(String) } + def self.[](env) + raise MissingEnvironmentVariables, "#{env} was not exported!" unless ENV[env] + + ENV.fetch(env) + end end require "extend/git_repository" # Where we link under -HOMEBREW_PREFIX = Pathname.new(get_env_or_raise("HOMEBREW_PREFIX")).freeze +HOMEBREW_PREFIX = Pathname(EnvVar["HOMEBREW_PREFIX"]).freeze # Where `.git` is found -HOMEBREW_REPOSITORY = Pathname.new(get_env_or_raise("HOMEBREW_REPOSITORY")) - .extend(GitRepositoryExtension) - .freeze +HOMEBREW_REPOSITORY = Pathname(EnvVar["HOMEBREW_REPOSITORY"]) + .extend(GitRepositoryExtension) + .freeze # Where we store most of Homebrew, taps, and various metadata -HOMEBREW_LIBRARY = Pathname.new(get_env_or_raise("HOMEBREW_LIBRARY")).freeze +HOMEBREW_LIBRARY = Pathname(EnvVar["HOMEBREW_LIBRARY"]).freeze # Where shim scripts for various build and SCM tools are stored HOMEBREW_SHIMS_PATH = (HOMEBREW_LIBRARY/"Homebrew/shims").freeze @@ -43,19 +51,19 @@ HOMEBREW_PINNED_KEGS = (HOMEBREW_PREFIX/"var/homebrew/pinned").freeze HOMEBREW_LOCKS = (HOMEBREW_PREFIX/"var/homebrew/locks").freeze # Where we store built products -HOMEBREW_CELLAR = Pathname.new(get_env_or_raise("HOMEBREW_CELLAR")).freeze +HOMEBREW_CELLAR = Pathname(EnvVar["HOMEBREW_CELLAR"]).freeze # Where downloads (bottles, source tarballs, etc.) are cached -HOMEBREW_CACHE = Pathname.new(get_env_or_raise("HOMEBREW_CACHE")).freeze +HOMEBREW_CACHE = Pathname(EnvVar["HOMEBREW_CACHE"]).freeze # Where brews installed via URL are cached HOMEBREW_CACHE_FORMULA = (HOMEBREW_CACHE/"Formula").freeze # Where build, postinstall, and test logs of formulae are written to -HOMEBREW_LOGS = Pathname.new(get_env_or_raise("HOMEBREW_LOGS")).expand_path.freeze +HOMEBREW_LOGS = Pathname(EnvVar["HOMEBREW_LOGS"]).expand_path.freeze # Must use `/tmp` instead of `TMPDIR` because long paths break Unix domain sockets -HOMEBREW_TEMP = Pathname.new(get_env_or_raise("HOMEBREW_TEMP")).yield_self do |tmp| +HOMEBREW_TEMP = Pathname(EnvVar["HOMEBREW_TEMP"]).yield_self do |tmp| tmp.mkpath unless tmp.exist? tmp.realpath end.freeze diff --git a/Library/Homebrew/cxxstdlib.rb b/Library/Homebrew/cxxstdlib.rb index 8750b0c187..e6ef4838d6 100644 --- a/Library/Homebrew/cxxstdlib.rb +++ b/Library/Homebrew/cxxstdlib.rb @@ -5,6 +5,8 @@ require "compilers" # Combination of C++ standard library and compiler. class CxxStdlib + extend T::Sig + include CompilerConstants # Error for when a formula's dependency was built with a different C++ standard library. @@ -72,6 +74,7 @@ class CxxStdlib type.to_s.gsub(/cxx$/, "c++") end + sig { returns(String) } def inspect "#<#{self.class.name}: #{compiler} #{type}>" end diff --git a/Library/Homebrew/debrew.rb b/Library/Homebrew/debrew.rb index 54a5b9af03..de551abc90 100644 --- a/Library/Homebrew/debrew.rb +++ b/Library/Homebrew/debrew.rb @@ -41,10 +41,13 @@ module Debrew # Module for displaying a debugging menu. class Menu + extend T::Sig + Entry = Struct.new(:name, :action) attr_accessor :prompt, :entries + sig { void } def initialize @entries = [] end diff --git a/Library/Homebrew/dependencies.rb b/Library/Homebrew/dependencies.rb index 2764048ce0..b3a12d9bff 100644 --- a/Library/Homebrew/dependencies.rb +++ b/Library/Homebrew/dependencies.rb @@ -8,6 +8,8 @@ require "cask_dependent" # # @api private class Dependencies < SimpleDelegator + extend T::Sig + def initialize(*args) super(args) end @@ -34,6 +36,7 @@ class Dependencies < SimpleDelegator build + required + recommended end + sig { returns(String) } def inspect "#<#{self.class.name}: #{to_a}>" end @@ -43,6 +46,8 @@ end # # @api private class Requirements < SimpleDelegator + extend T::Sig + def initialize(*args) super(Set.new(args)) end @@ -59,6 +64,7 @@ class Requirements < SimpleDelegator self end + sig { returns(String) } def inspect "#<#{self.class.name}: {#{to_a.join(", ")}}>" end diff --git a/Library/Homebrew/dependency.rb b/Library/Homebrew/dependency.rb index 99b8a0a1ee..21a7d7e78c 100644 --- a/Library/Homebrew/dependency.rb +++ b/Library/Homebrew/dependency.rb @@ -7,6 +7,8 @@ require "dependable" # # @api private class Dependency + extend T::Sig + extend Forwardable include Dependable @@ -64,6 +66,7 @@ class Dependency env_proc&.call end + sig { returns(String) } def inspect "#<#{self.class.name}: #{name.inspect} #{tags.inspect}>" end @@ -78,6 +81,8 @@ class Dependency end class << self + extend T::Sig + # Expand the dependencies of each dependent recursively, optionally yielding # `[dependent, dep]` pairs to allow callers to apply arbitrary filters to # the list. @@ -115,9 +120,9 @@ class Dependency @expand_stack.pop end - def action(dependent, dep, &_block) + def action(dependent, dep, &block) catch(:action) do - if block_given? + if block yield dependent, dep elsif dep.optional? || dep.recommended? prune unless dependent.build.with?(dep) @@ -126,16 +131,19 @@ class Dependency end # Prune a dependency and its dependencies recursively. + sig { void } def prune throw(:action, :prune) end # Prune a single dependency but do not prune its dependencies. + sig { void } def skip throw(:action, :skip) end # Keep a dependency, but prune its dependencies. + sig { void } def keep_but_prune_recursive_deps throw(:action, :keep_but_prune_recursive_deps) end diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index 80b8dbab0f..c375139955 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -18,10 +18,13 @@ require "extend/cachable" # This class is used by `depends_on` in the formula DSL to turn dependency # specifications into the proper kinds of dependencies and requirements. class DependencyCollector + extend T::Sig + extend Cachable attr_reader :deps, :requirements + sig { void } def initialize @deps = Dependencies.new @requirements = Requirements.new @@ -112,8 +115,6 @@ class DependencyCollector def parse_string_spec(spec, tags) if spec.match?(HOMEBREW_TAP_FORMULA_REGEX) TapDependency.new(spec, tags) - elsif tags.empty? - Dependency.new(spec, tags) else Dependency.new(spec, tags) end diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 153b904909..c7082b7f42 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -16,19 +16,24 @@ require "missing_formula" require "digest" require "cli/parser" require "json" +require "formula_auditor" +require "tap_auditor" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def audit_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `audit` [] [] + `audit` [] [|] Check for Homebrew coding style violations. This should be run before - submitting a new formula. If no are provided, check all locally - available formulae and skip style checks. Will exit with a non-zero status if any - errors are found. + submitting a new formula or cask. If no | are provided, check all + locally available formulae and casks and skip style checks. Will exit with a + non-zero status if any errors are found. EOS switch "--strict", description: "Run additional, stricter style checks." @@ -36,8 +41,8 @@ module Homebrew description: "Run additional, slower style checks that navigate the Git repository." switch "--online", description: "Run additional, slower style checks that require a network connection." - switch "--new-formula", - description: "Run various additional style checks to determine if a new formula is eligible "\ + switch "--new", "--new-formula", "--new-cask", + description: "Run various additional style checks to determine if a new formula or cask is eligible "\ "for Homebrew. This should be used when creating new formula and implies "\ "`--strict` and `--online`." flag "--tap=", @@ -51,7 +56,7 @@ module Homebrew "make output easy to grep." switch "--skip-style", description: "Skip running non-RuboCop style checks. Useful if you plan on running "\ - "`brew style` separately. Default unless a formula is specified by name" + "`brew style` separately. Enabled by default unless a formula is specified by name." switch "-D", "--audit-debug", description: "Enable debugging and profiling of audit methods." comma_array "--only", @@ -67,6 +72,18 @@ module Homebrew description: "Specify a comma-separated list to skip checking for violations of the listed "\ "RuboCop cops." + switch "--formula", "--formulae", + description: "Treat all named arguments as formulae." + switch "--cask", "--casks", + description: "Treat all named arguments as casks." + + switch "--[no-]appcast", + description: "Audit the appcast" + switch "--token-conflicts", + description: "Audit for token conflicts" + + conflicts "--formula", "--cask" + conflicts "--only", "--except" conflicts "--only-cops", "--except-cops", "--strict" conflicts "--only-cops", "--except-cops", "--only" @@ -76,6 +93,7 @@ module Homebrew end end + sig { void } def audit args = audit_args.parse @@ -92,30 +110,39 @@ module Homebrew git = args.git? skip_style = args.skip_style? || args.no_named? || args.tap + only = :formula if args.formula? && !args.cask? + only = :cask if args.cask? && !args.formula? + ENV.activate_extensions! ENV.setup_build_environment - audit_formulae = if args.tap - Tap.fetch(args.tap).formula_names.map { |name| Formula[name] } + audit_formulae, audit_casks = if args.tap + Tap.fetch(args.tap).yield_self do |tap| + [ + tap.formula_names.map { |name| Formula[name] }, + tap.cask_files.map { |path| Cask::CaskLoader.load(path) }, + ] + end elsif args.no_named? - Formula + [Formula, Cask::Cask.to_a] else - args.named.to_resolved_formulae + args.named.to_formulae_and_casks(only: only) + .partition { |formula_or_cask| formula_or_cask.is_a?(Formula) } end - style_files = args.named.to_formulae_paths unless skip_style + style_files = args.named.to_paths unless skip_style only_cops = args.only_cops except_cops = args.except_cops - options = { fix: args.fix?, debug: args.debug?, verbose: args.verbose? } + style_options = { fix: args.fix?, debug: args.debug?, verbose: args.verbose? } if only_cops - options[:only_cops] = only_cops + style_options[:only_cops] = only_cops elsif args.new_formula? nil elsif except_cops - options[:except_cops] = except_cops + style_options[:except_cops] = except_cops elsif !strict - options[:except_cops] = [:FormulaAuditStrict] + style_options[:except_cops] = [:FormulaAuditStrict] end # Run tap audits first @@ -124,7 +151,7 @@ module Homebrew Tap.each do |tap| next if args.tap && tap != args.tap - ta = TapAuditor.new tap, strict: args.strict? + ta = TapAuditor.new(tap, strict: args.strict?) ta.audit next if ta.problems.blank? @@ -137,7 +164,7 @@ module Homebrew end # Check style in a single batch run up front for performance - style_offenses = Style.check_style_json(style_files, options) if style_files + style_offenses = Style.check_style_json(style_files, style_options) if style_files # load licenses spdx_license_data = SPDX.license_data spdx_exception_data = SPDX.exception_data @@ -154,20 +181,20 @@ module Homebrew spdx_license_data: spdx_license_data, spdx_exception_data: spdx_exception_data, tap_audit_exceptions: f.tap.audit_exceptions, - } - options[:style_offenses] = style_offenses.for_path(f.path) if style_offenses - options[:display_cop_names] = args.display_cop_names? - options[:build_stable] = args.build_stable? + style_offenses: style_offenses ? style_offenses.for_path(f.path) : nil, + display_cop_names: args.display_cop_names?, + build_stable: args.build_stable?, + }.compact - fa = FormulaAuditor.new(f, options) + fa = FormulaAuditor.new(f, **options) fa.audit next if fa.problems.empty? && fa.new_formula_problems.empty? formula_count += 1 problem_count += fa.problems.size problem_lines = format_problem_lines(fa.problems) - corrected_problem_count = options[:style_offenses].count(&:corrected?) if options[:style_offenses] - new_formula_problem_lines = format_problem_lines(fa.new_formula_problems) + corrected_problem_count += options.fetch(:style_offenses, []).count(&:corrected?) + new_formula_problem_lines += format_problem_lines(fa.new_formula_problems) if args.display_filename? puts problem_lines.map { |s| "#{f.path}: #{s}" } else @@ -184,24 +211,49 @@ module Homebrew end end - new_formula_problem_count += new_formula_problem_lines.size - puts new_formula_problem_lines.map { |s| " #{s}" } + casks_results = if audit_casks.empty? + [] + else + require "cask/cmd/audit" - total_problems_count = problem_count + new_formula_problem_count + tap_problem_count + Cask::Cmd::Audit.audit_casks( + *audit_casks, + download: nil, + appcast: args.appcast?, + online: args.online?, + strict: args.strict?, + new_cask: args.new_cask?, + token_conflicts: args.token_conflicts?, + quarantine: nil, + language: nil, + ) + end + + failed_casks = casks_results.reject { |_, result| result[:errors].empty? } + + cask_count = failed_casks.count + + cask_problem_count = failed_casks.sum { |_, result| result[:warnings].count + result[:errors].count } + new_formula_problem_count += new_formula_problem_lines.count + total_problems_count = problem_count + new_formula_problem_count + cask_problem_count + tap_problem_count return unless total_problems_count.positive? - problem_plural = "#{total_problems_count} #{"problem".pluralize(total_problems_count)}" - formula_plural = "#{formula_count} #{"formula".pluralize(formula_count)}" - tap_plural = "#{tap_count} #{"tap".pluralize(tap_count)}" - corrected_problem_plural = "#{corrected_problem_count} #{"problem".pluralize(corrected_problem_count)}" - errors_summary = if tap_count.zero? - "#{problem_plural} in #{formula_plural} detected" - elsif formula_count.zero? - "#{problem_plural} in #{tap_plural} detected" - else - "#{problem_plural} in #{formula_plural} and #{tap_plural} detected" + puts new_formula_problem_lines.map { |s| " #{s}" } + + errors_summary = "#{total_problems_count} #{"problem".pluralize(total_problems_count)}" + + error_sources = [] + error_sources << "#{formula_count} #{"formula".pluralize(formula_count)}" if formula_count.positive? + error_sources << "#{cask_count} #{"cask".pluralize(cask_count)}" if cask_count.positive? + error_sources << "#{tap_count} #{"tap".pluralize(tap_count)}" if tap_count.positive? + + errors_summary += " in #{error_sources.to_sentence}" if error_sources.any? + + errors_summary += " detected" + + if corrected_problem_count.positive? + errors_summary += ", #{corrected_problem_count} #{"problem".pluralize(corrected_problem_count)} corrected" end - errors_summary += ", #{corrected_problem_plural} corrected" if corrected_problem_count.positive? ofail errors_summary end @@ -214,1030 +266,4 @@ module Homebrew def format_problem(message, location) "* #{location&.to_s&.dup&.concat(": ")}#{message.chomp.gsub("\n", "\n ")}" end - - class FormulaText - def initialize(path) - @text = path.open("rb", &:read) - @lines = @text.lines.to_a - end - - def without_patch - @text.split("\n__END__").first - end - - def trailing_newline? - /\Z\n/ =~ @text - end - - def =~(other) - other =~ @text - end - - def include?(s) - @text.include? s - end - - def line_number(regex, skip = 0) - index = @lines.drop(skip).index { |line| line =~ regex } - index ? index + 1 : nil - end - - def reverse_line_number(regex) - index = @lines.reverse.index { |line| line =~ regex } - index ? @lines.count - index : nil - end - end - - class FormulaAuditor - include FormulaCellarChecks - - attr_reader :formula, :text, :problems, :new_formula_problems - - def initialize(formula, options = {}) - @formula = formula - @versioned_formula = formula.versioned_formula? - @new_formula_inclusive = options[:new_formula] - @new_formula = options[:new_formula] && !@versioned_formula - @strict = options[:strict] - @online = options[:online] - @build_stable = options[:build_stable] - @git = options[:git] - @display_cop_names = options[:display_cop_names] - @only = options[:only] - @except = options[:except] - # Accept precomputed style offense results, for efficiency - @style_offenses = options[:style_offenses] - # Allow the formula tap to be set as homebrew/core, for testing purposes - @core_tap = formula.tap&.core_tap? || options[:core_tap] - @problems = [] - @new_formula_problems = [] - @text = FormulaText.new(formula.path) - @specs = %w[stable head].map { |s| formula.send(s) }.compact - @spdx_license_data = options[:spdx_license_data] - @spdx_exception_data = options[:spdx_exception_data] - @tap_audit_exceptions = options[:tap_audit_exceptions] - end - - def audit_style - return unless @style_offenses - - @style_offenses.each do |offense| - correction_status = "#{Tty.green}[Corrected]#{Tty.reset} " if offense.corrected? - - cop_name = "#{offense.cop_name}: " if @display_cop_names - message = "#{cop_name}#{correction_status}#{offense.message}" - - problem message, location: offense.location - end - end - - def audit_file - if formula.core_formula? && @versioned_formula - unversioned_formula = begin - # build this ourselves as we want e.g. homebrew/core to be present - full_name = if formula.tap - "#{formula.tap}/#{formula.name}" - else - formula.name - end - Formulary.factory(full_name.gsub(/@.*$/, "")).path - rescue FormulaUnavailableError, TapFormulaAmbiguityError, - TapFormulaWithOldnameAmbiguityError - Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb") - end - unless unversioned_formula.exist? - unversioned_name = unversioned_formula.basename(".rb") - problem "#{formula} is versioned but no #{unversioned_name} formula exists" - end - elsif @build_stable && - formula.stable? && - !@versioned_formula && - (versioned_formulae = formula.versioned_formulae - [formula]) && - versioned_formulae.present? - versioned_aliases = formula.aliases.grep(/.@\d/) - _, last_alias_version = versioned_formulae.map(&:name).last.split("@") - alias_name_major = "#{formula.name}@#{formula.version.major}" - alias_name_major_minor = "#{alias_name_major}.#{formula.version.minor}" - alias_name = if last_alias_version.split(".").length == 1 - alias_name_major - else - alias_name_major_minor - end - valid_alias_names = [alias_name_major, alias_name_major_minor] - - unless @core_tap - versioned_aliases.map! { |a| "#{formula.tap}/#{a}" } - valid_alias_names.map! { |a| "#{formula.tap}/#{a}" } - end - - # Fix naming based on what people expect. - if alias_name_major_minor == "adoptopenjdk@1.8" - valid_alias_names << "adoptopenjdk@8" - valid_alias_names.delete "adoptopenjdk@1" - end - - valid_versioned_aliases = versioned_aliases & valid_alias_names - invalid_versioned_aliases = versioned_aliases - valid_alias_names - - if valid_versioned_aliases.empty? - if formula.tap - problem <<~EOS - Formula has other versions so create a versioned alias: - cd #{formula.tap.alias_dir} - ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name} - EOS - else - problem "Formula has other versions so create an alias named #{alias_name}." - end - end - - if invalid_versioned_aliases.present? - problem <<~EOS - Formula has invalid versioned aliases: - #{invalid_versioned_aliases.join("\n ")} - EOS - end - end - end - - def self.aliases - # core aliases + tap alias names + tap alias full name - @aliases ||= Formula.aliases + Formula.tap_aliases - end - - def audit_formula_name - return unless @strict - return unless @core_tap - - name = formula.name - - problem "'#{name}' is not allowed in homebrew/core." if MissingFormula.disallowed_reason(name) - - if Formula.aliases.include? name - problem "Formula name conflicts with existing aliases in homebrew/core." - return - end - - if oldname = CoreTap.instance.formula_renames[name] - problem "'#{name}' is reserved as the old name of #{oldname} in homebrew/core." - return - end - - return if formula.core_formula? - return unless Formula.core_names.include?(name) - - problem "Formula name conflicts with existing core formula." - end - - PROVIDED_BY_MACOS_DEPENDS_ON_ALLOWLIST = %w[ - apr - apr-util - libressl - openblas - openssl@1.1 - ].freeze - - PERMITTED_LICENSE_MISMATCHES = { - "AGPL-3.0" => ["AGPL-3.0-only", "AGPL-3.0-or-later"], - "GPL-2.0" => ["GPL-2.0-only", "GPL-2.0-or-later"], - "GPL-3.0" => ["GPL-3.0-only", "GPL-3.0-or-later"], - "LGPL-2.1" => ["LGPL-2.1-only", "LGPL-2.1-or-later"], - "LGPL-3.0" => ["LGPL-3.0-only", "LGPL-3.0-or-later"], - }.freeze - - PERMITTED_FORMULA_LICENSE_MISMATCHES = { - "cmockery" => "0.1.2", - "scw@1" => "1.20", - }.freeze - - def audit_license - if formula.license.present? - licenses, exceptions = SPDX.parse_license_expression formula.license - - non_standard_licenses = licenses.reject { |license| SPDX.valid_license? license } - if non_standard_licenses.present? - problem <<~EOS - Formula #{formula.name} contains non-standard SPDX licenses: #{non_standard_licenses}. - For a list of valid licenses check: #{Formatter.url("https://spdx.org/licenses/")} - EOS - end - - if @strict - deprecated_licenses = licenses.select do |license| - SPDX.deprecated_license? license - end - if deprecated_licenses.present? - problem <<~EOS - Formula #{formula.name} contains deprecated SPDX licenses: #{deprecated_licenses}. - You may need to add `-only` or `-or-later` for GNU licenses (e.g. `GPL`, `LGPL`, `AGPL`, `GFDL`). - For a list of valid licenses check: #{Formatter.url("https://spdx.org/licenses/")} - EOS - end - end - - invalid_exceptions = exceptions.reject { |exception| SPDX.valid_license_exception? exception } - if invalid_exceptions.present? - problem <<~EOS - Formula #{formula.name} contains invalid or deprecated SPDX license exceptions: #{invalid_exceptions}. - For a list of valid license exceptions check: - #{Formatter.url("https://spdx.org/licenses/exceptions-index.html")} - EOS - end - - return unless @online - - user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) - return if user.blank? - - github_license = GitHub.get_repo_license(user, repo) - return unless github_license - return if (licenses + ["NOASSERTION"]).include?(github_license) - return if PERMITTED_LICENSE_MISMATCHES[github_license]&.any? { |license| licenses.include? license } - return if PERMITTED_FORMULA_LICENSE_MISMATCHES[formula.name] == formula.version - - problem "Formula license #{licenses} does not match GitHub license #{Array(github_license)}." - - elsif @new_formula && @core_tap - problem "Formulae in homebrew/core must specify a license." - end - end - - # TODO: try to remove these, it's not a good user experience - VERSIONED_DEPENDENCIES_CONFLICTS_ALLOWLIST = %w[ - agda - anjuta - fdroidserver - gradio - predictionio - sqoop - visp - ].freeze - - def audit_deps - @specs.each do |spec| - # Check for things we don't like to depend on. - # We allow non-Homebrew installs whenever possible. - spec.deps.each do |dep| - begin - dep_f = dep.to_formula - rescue TapFormulaUnavailableError - # Don't complain about missing cross-tap dependencies - next - rescue FormulaUnavailableError - problem "Can't find dependency #{dep.name.inspect}." - next - rescue TapFormulaAmbiguityError - problem "Ambiguous dependency #{dep.name.inspect}." - next - rescue TapFormulaWithOldnameAmbiguityError - problem "Ambiguous oldname dependency #{dep.name.inspect}." - next - end - - if dep_f.oldname && dep.name.split("/").last == dep_f.oldname - problem "Dependency '#{dep.name}' was renamed; use new name '#{dep_f.name}'." - end - - if self.class.aliases.include?(dep.name) && - dep_f.core_formula? && !dep_f.versioned_formula? - problem "Dependency '#{dep.name}' from homebrew/core is an alias; " \ - "use the canonical name '#{dep.to_formula.full_name}'." - end - - if @core_tap && - @new_formula && - dep_f.keg_only? && - dep_f.keg_only_reason.provided_by_macos? && - dep_f.keg_only_reason.applicable? && - !PROVIDED_BY_MACOS_DEPENDS_ON_ALLOWLIST.include?(dep.name) - new_formula_problem( - "Dependency '#{dep.name}' is provided by macOS; " \ - "please replace 'depends_on' with 'uses_from_macos'.", - ) - end - - dep.options.each do |opt| - next if @core_tap - next if dep_f.option_defined?(opt) - next if dep_f.requirements.find do |r| - if r.recommended? - opt.name == "with-#{r.name}" - elsif r.optional? - opt.name == "without-#{r.name}" - end - end - - problem "Dependency #{dep} does not define option #{opt.name.inspect}" - end - - problem "Don't use git as a dependency (it's always available)" if @new_formula && dep.name == "git" - - problem "Dependency '#{dep.name}' is marked as :run. Remove :run; it is a no-op." if dep.tags.include?(:run) - - next unless @core_tap - - if dep.tags.include?(:recommended) || dep.tags.include?(:optional) - problem "Formulae in homebrew/core should not have optional or recommended dependencies" - end - end - - next unless @core_tap - - if spec.requirements.map(&:recommended?).any? || spec.requirements.map(&:optional?).any? - problem "Formulae in homebrew/core should not have optional or recommended requirements" - end - end - - return unless @core_tap - return if VERSIONED_DEPENDENCIES_CONFLICTS_ALLOWLIST.include?(formula.name) - - # The number of conflicts on Linux is absurd. - # TODO: remove this and check these there too. - return if OS.linux? - - recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false) - version_hash = {} - version_conflicts = Set.new - recursive_runtime_formulae.each do |f| - name = f.name - unversioned_name, = name.split("@") - version_hash[unversioned_name] ||= Set.new - version_hash[unversioned_name] << name - next if version_hash[unversioned_name].length < 2 - - version_conflicts += version_hash[unversioned_name] - end - - return if version_conflicts.empty? - - problem <<~EOS - #{formula.full_name} contains conflicting version recursive dependencies: - #{version_conflicts.to_a.join ", "} - View these with `brew deps --tree #{formula.full_name}`. - EOS - end - - def audit_conflicts - formula.conflicts.each do |c| - Formulary.factory(c.name) - rescue TapFormulaUnavailableError - # Don't complain about missing cross-tap conflicts. - next - rescue FormulaUnavailableError - problem "Can't find conflicting formula #{c.name.inspect}." - rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError - problem "Ambiguous conflicting formula #{c.name.inspect}." - end - end - - def audit_postgresql - return unless formula.name == "postgresql" - return unless @core_tap - - major_version = formula.version.major.to_i - previous_major_version = major_version - 1 - previous_formula_name = "postgresql@#{previous_major_version}" - begin - Formula[previous_formula_name] - rescue FormulaUnavailableError - problem "Versioned #{previous_formula_name} in homebrew/core must be created for " \ - "`brew-postgresql-upgrade-database` and `pg_upgrade` to work." - end - end - - # openssl@1.1 only needed for Linux - VERSIONED_KEG_ONLY_ALLOWLIST = %w[ - autoconf@2.13 - bash-completion@2 - clang-format@8 - gnupg@1.4 - libsigc++@2 - lua@5.1 - numpy@1.16 - openssl@1.1 - python@3.8 - python@3.9 - ].freeze - - def audit_versioned_keg_only - return unless @versioned_formula - return unless @core_tap - - if formula.keg_only? - return if formula.keg_only_reason.versioned_formula? - if formula.name.start_with?("openssl", "libressl") && - formula.keg_only_reason.by_macos? - return - end - end - - return if VERSIONED_KEG_ONLY_ALLOWLIST.include?(formula.name) - return if formula.name.start_with?("adoptopenjdk@") - return if formula.name.start_with?("gcc@") - - problem "Versioned formulae in homebrew/core should use `keg_only :versioned_formula`" - end - - CERT_ERROR_ALLOWLIST = { - "hashcat" => "https://hashcat.net/hashcat/", - "jinx" => "https://www.jinx-lang.org/", - "lmod" => "https://www.tacc.utexas.edu/research-development/tacc-projects/lmod", - "micropython" => "https://www.micropython.org/", - "monero" => "https://www.getmonero.org/", - }.freeze - - def audit_homepage - homepage = formula.homepage - - return if homepage.nil? || homepage.empty? - - return unless @online - - return if CERT_ERROR_ALLOWLIST[formula.name] == homepage - - return unless DevelopmentTools.curl_handles_most_https_certificates? - - if http_content_problem = curl_check_http_content(homepage, - user_agents: [:browser, :default], - check_content: true, - strict: @strict) - problem http_content_problem - end - end - - def audit_bottle_spec - # special case: new versioned formulae should be audited - return unless @new_formula_inclusive - return unless @core_tap - - return if formula.bottle_disabled? - - return unless formula.bottle_defined? - - new_formula_problem "New formulae in homebrew/core should not have a `bottle do` block" - end - - def audit_bottle_disabled - return unless formula.bottle_disabled? - return if formula.bottle_unneeded? - - problem "Unrecognized bottle modifier" unless formula.bottle_disable_reason.valid? - - return unless @core_tap - - problem "Formulae in homebrew/core should not use `bottle :disabled`" - end - - def audit_github_repository_archived - return if formula.deprecated? - - user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @online - return if user.blank? - - metadata = SharedAudits.github_repo_data(user, repo) - return if metadata.nil? - - problem "GitHub repo is archived" if metadata["archived"] - end - - def audit_gitlab_repository_archived - return if formula.deprecated? - - user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if @online - return if user.blank? - - metadata = SharedAudits.gitlab_repo_data(user, repo) - return if metadata.nil? - - problem "GitLab repo is archived" if metadata["archived"] - end - - def audit_github_repository - user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula - - return if user.blank? - - warning = SharedAudits.github(user, repo) - return if warning.nil? - - new_formula_problem warning - end - - def audit_gitlab_repository - user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if @new_formula - return if user.blank? - - warning = SharedAudits.gitlab(user, repo) - return if warning.nil? - - new_formula_problem warning - end - - def audit_bitbucket_repository - user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*}) if @new_formula - return if user.blank? - - warning = SharedAudits.bitbucket(user, repo) - return if warning.nil? - - new_formula_problem warning - end - - def get_repo_data(regex) - return unless @core_tap - return unless @online - - _, user, repo = *regex.match(formula.stable.url) if formula.stable - _, user, repo = *regex.match(formula.homepage) unless user - _, user, repo = *regex.match(formula.head.url) if !user && formula.head - return if !user || !repo - - repo.delete_suffix!(".git") - - [user, repo] - end - - UNSTABLE_ALLOWLIST = { - "aalib" => "1.4rc", - "automysqlbackup" => "3.0-rc", - "aview" => "1.3.0rc", - "elm-format" => "0.6.0-alpha", - "ftgl" => "2.1.3-rc", - "hidapi" => "0.8.0-rc", - "libcaca" => "0.99b", - "premake" => "4.4-beta", - "pwnat" => "0.3-beta", - "recode" => "3.7-beta", - "speexdsp" => "1.2rc", - "sqoop" => "1.4.", - "tcptraceroute" => "1.5beta", - "tiny-fugue" => "5.0b", - "vbindiff" => "3.0_beta", - }.freeze - - # Used for formulae that are unstable but need CI run without being in homebrew/core - UNSTABLE_DEVEL_ALLOWLIST = { - }.freeze - - GNOME_DEVEL_ALLOWLIST = { - "libart" => "2.3", - "gtk-mac-integration" => "2.1", - "gtk-doc" => "1.31", - "gcab" => "1.3", - "libepoxy" => "1.5", - }.freeze - - def audit_specs - problem "Head-only (no stable download)" if head_only?(formula) - - %w[Stable HEAD].each do |name| - spec_name = name.downcase.to_sym - next unless spec = formula.send(spec_name) - - ra = ResourceAuditor.new(spec, spec_name, online: @online, strict: @strict).audit - ra.problems.each do |message| - problem "#{name}: #{message}" - end - - spec.resources.each_value do |resource| - problem "Resource name should be different from the formula name" if resource.name == formula.name - - ra = ResourceAuditor.new(resource, spec_name, online: @online, strict: @strict).audit - ra.problems.each do |message| - problem "#{name} resource #{resource.name.inspect}: #{message}" - end - end - - next if spec.patches.empty? - next unless @new_formula - - new_formula_problem( - "Formulae should not require patches to build. " \ - "Patches should be submitted and accepted upstream first.", - ) - end - - if stable = formula.stable - version = stable.version - problem "Stable: version (#{version}) is set to a string without a digit" if version.to_s !~ /\d/ - if version.to_s.start_with?("HEAD") - problem "Stable: non-HEAD version name (#{version}) should not begin with HEAD" - end - end - - return unless @core_tap - - if formula.head && @versioned_formula && - !tap_audit_exception(:versioned_head_spec_allowlist, formula.name) - problem "Versioned formulae should not have a `HEAD` spec" - end - - stable = formula.stable - return unless stable - return unless stable.url - - stable_version_string = stable.version.to_s - stable_url_version = Version.parse(stable.url) - stable_url_minor_version = stable_url_version.minor.to_i - - formula_suffix = stable.version.patch.to_i - throttled_rate = tap_audit_exception(:throttled_formulae, formula.name) - if throttled_rate && formula_suffix.modulo(throttled_rate).nonzero? - problem "should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}" - end - - case (url = stable.url) - when /[\d._-](alpha|beta|rc\d)/ - matched = Regexp.last_match(1) - version_prefix = stable_version_string.sub(/\d+$/, "") - return if UNSTABLE_ALLOWLIST[formula.name] == version_prefix - return if UNSTABLE_DEVEL_ALLOWLIST[formula.name] == version_prefix - - problem "Stable version URLs should not contain #{matched}" - when %r{download\.gnome\.org/sources}, %r{ftp\.gnome\.org/pub/GNOME/sources}i - version_prefix = stable.version.major_minor - return if GNOME_DEVEL_ALLOWLIST[formula.name] == version_prefix - return if stable_url_version < Version.create("1.0") - return if stable_url_minor_version.even? - - problem "#{stable.version} is a development release" - when %r{isc.org/isc/bind\d*/}i - return if stable_url_minor_version.even? - - problem "#{stable.version} is a development release" - - when %r{https?://gitlab\.com/([\w-]+)/([\w-]+)} - owner = Regexp.last_match(1) - repo = Regexp.last_match(2) - - tag = SharedAudits.gitlab_tag_from_url(url) - tag ||= stable.specs[:tag] - tag ||= stable.version - - if @online - error = SharedAudits.gitlab_release(owner, repo, tag, formula: formula) - problem error if error - end - when %r{^https://github.com/([\w-]+)/([\w-]+)} - owner = Regexp.last_match(1) - repo = Regexp.last_match(2) - tag = SharedAudits.github_tag_from_url(url) - tag ||= formula.stable.specs[:tag] - - if @online - error = SharedAudits.github_release(owner, repo, tag, formula: formula) - problem error if error - end - end - end - - def audit_revision_and_version_scheme - return unless @git - return unless formula.tap # skip formula not from core or any taps - return unless formula.tap.git? # git log is required - return if formula.stable.blank? - - fv = FormulaVersions.new(formula) - - current_version = formula.stable.version - current_checksum = formula.stable.checksum - current_version_scheme = formula.version_scheme - current_revision = formula.revision - current_url = formula.stable.url - - previous_version = nil - previous_version_scheme = nil - previous_revision = nil - - newest_committed_version = nil - newest_committed_checksum = nil - newest_committed_revision = nil - newest_committed_url = nil - - fv.rev_list("origin/master") do |rev| - fv.formula_at_revision(rev) do |f| - stable = f.stable - next if stable.blank? - - previous_version = stable.version - previous_checksum = stable.checksum - previous_version_scheme = f.version_scheme - previous_revision = f.revision - - newest_committed_version ||= previous_version - newest_committed_checksum ||= previous_checksum - newest_committed_revision ||= previous_revision - newest_committed_url ||= stable.url - end - - break if previous_version && current_version != previous_version - break if previous_revision && current_revision != previous_revision - end - - if current_version == newest_committed_version && - current_url == newest_committed_url && - current_checksum != newest_committed_checksum - problem( - "stable sha256 changed without the url/version also changing; " \ - "please create an issue upstream to rule out malicious " \ - "circumstances and to find out why the file changed.", - ) - end - - if !newest_committed_version.nil? && - current_version < newest_committed_version && - current_version_scheme == previous_version_scheme - problem "stable version should not decrease (from #{newest_committed_version} to #{current_version})" - end - - unless previous_version_scheme.nil? - if current_version_scheme < previous_version_scheme - problem "version_scheme should not decrease (from #{previous_version_scheme} " \ - "to #{current_version_scheme})" - elsif current_version_scheme > (previous_version_scheme + 1) - problem "version_schemes should only increment by 1" - end - end - - if (previous_version != newest_committed_version || - current_version != newest_committed_version) && - !current_revision.zero? && - current_revision == newest_committed_revision && - current_revision == previous_revision - problem "'revision #{current_revision}' should be removed" - elsif current_version == previous_version && - !previous_revision.nil? && - current_revision < previous_revision - problem "revision should not decrease (from #{previous_revision} to #{current_revision})" - elsif newest_committed_revision && - current_revision > (newest_committed_revision + 1) - problem "revisions should only increment by 1" - end - end - - def audit_text - bin_names = Set.new - bin_names << formula.name - bin_names += formula.aliases - [formula.bin, formula.sbin].each do |dir| - next unless dir.exist? - - bin_names += dir.children.map(&:basename).map(&:to_s) - end - shell_commands = ["system", "shell_output", "pipe_output"] - bin_names.each do |name| - shell_commands.each do |cmd| - if text.to_s.match?(/test do.*#{cmd}[(\s]+['"]#{Regexp.escape(name)}[\s'"]/m) - problem %Q(fully scope test #{cmd} calls, e.g. #{cmd} "\#{bin}/#{name}") - end - end - end - end - - def audit_reverse_migration - # Only enforce for new formula being re-added to core - return unless @strict - return unless @core_tap - return unless formula.tap.tap_migrations.key?(formula.name) - - problem <<~EOS - #{formula.name} seems to be listed in tap_migrations.json! - Please remove #{formula.name} from present tap & tap_migrations.json - before submitting it to Homebrew/homebrew-#{formula.tap.repo}. - EOS - end - - def audit_prefix_has_contents - return unless formula.prefix.directory? - return unless Keg.new(formula.prefix).empty_installation? - - problem <<~EOS - The installation seems to be empty. Please ensure the prefix - is set correctly and expected files are installed. - The prefix configure/make argument may be case-sensitive. - EOS - end - - def quote_dep(dep) - dep.is_a?(Symbol) ? dep.inspect : "'#{dep}'" - end - - def problem_if_output(output) - problem(output) if output - end - - def audit - only_audits = @only - except_audits = @except - - methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name| - name = audit_method_name.delete_prefix("audit_") - if only_audits - next unless only_audits.include?(name) - elsif except_audits - next if except_audits.include?(name) - end - send(audit_method_name) - end - end - - private - - def problem(message, location: nil) - @problems << ({ message: message, location: location }) - end - - def new_formula_problem(message, location: nil) - @new_formula_problems << ({ message: message, location: location }) - end - - def head_only?(formula) - formula.head && formula.stable.nil? - end - - def tap_audit_exception(list, formula, value = nil) - return false unless @tap_audit_exceptions.key? list - - list = @tap_audit_exceptions[list] - - case list - when Array - list.include? formula - when Hash - return false unless list.include? formula - return list[formula] if value.blank? - - list[formula] == value - end - end - end - - class ResourceAuditor - attr_reader :name, :version, :checksum, :url, :mirrors, :using, :specs, :owner, :spec_name, :problems - - def initialize(resource, spec_name, options = {}) - @name = resource.name - @version = resource.version - @checksum = resource.checksum - @url = resource.url - @mirrors = resource.mirrors - @using = resource.using - @specs = resource.specs - @owner = resource.owner - @spec_name = spec_name - @online = options[:online] - @strict = options[:strict] - @problems = [] - end - - def audit - audit_version - audit_download_strategy - audit_urls - self - end - - def audit_version - if version.nil? - problem "missing version" - elsif !version.detected_from_url? - version_text = version - version_url = Version.detect(url, **specs) - if version_url.to_s == version_text.to_s && version.instance_of?(Version) - problem "version #{version_text} is redundant with version scanned from URL" - end - end - end - - def audit_download_strategy - url_strategy = DownloadStrategyDetector.detect(url) - - if (using == :git || url_strategy == GitDownloadStrategy) && specs[:tag] && !specs[:revision] - problem "Git should specify :revision when a :tag is specified." - end - - return unless using - - if using == :cvs - mod = specs[:module] - - problem "Redundant :module value in URL" if mod == name - - if url.match?(%r{:[^/]+$}) - mod = url.split(":").last - - if mod == name - problem "Redundant CVS module appended to URL" - else - problem "Specify CVS module as `:module => \"#{mod}\"` instead of appending it to the URL" - end - end - end - - return unless url_strategy == DownloadStrategyDetector.detect("", using) - - problem "Redundant :using value in URL" - end - - def self.curl_openssl_and_deps - @curl_openssl_and_deps ||= begin - formulae_names = ["curl", "openssl"] - formulae_names += formulae_names.flat_map do |f| - Formula[f].recursive_dependencies.map(&:name) - end - formulae_names.uniq - rescue FormulaUnavailableError - [] - end - end - - def audit_urls - return unless @online - - urls = [url] + mirrors - urls.each do |url| - next if !@strict && mirrors.include?(url) - - strategy = DownloadStrategyDetector.detect(url, using) - if strategy <= CurlDownloadStrategy && !url.start_with?("file") - # A `brew mirror`'ed URL is usually not yet reachable at the time of - # pull request. - next if url.match?(%r{^https://dl.bintray.com/homebrew/mirror/}) - - if http_content_problem = curl_check_http_content(url) - problem http_content_problem - end - elsif strategy <= GitDownloadStrategy - problem "The URL #{url} is not a valid git URL" unless Utils::Git.remote_exists? url - elsif strategy <= SubversionDownloadStrategy - next unless DevelopmentTools.subversion_handles_most_https_certificates? - next unless Utils::Svn.available? - - problem "The URL #{url} is not a valid svn URL" unless Utils::Svn.remote_exists? url - end - end - end - - def problem(text) - @problems << text - end - end - - class TapAuditor - attr_reader :name, :path, :tap_audit_exceptions, :problems - - def initialize(tap, strict:) - @name = tap.name - @path = tap.path - @tap_audit_exceptions = tap.audit_exceptions - @problems = [] - end - - def audit - audit_json_files - audit_tap_audit_exceptions - end - - def audit_json_files - json_patterns = Tap::HOMEBREW_TAP_JSON_FILES.map { |pattern| @path/pattern } - Pathname.glob(json_patterns).each do |file| - JSON.parse file.read - rescue JSON::ParserError - problem "#{file.to_s.delete_prefix("#{@path}/")} contains invalid JSON" - end - end - - def audit_tap_audit_exceptions - @tap_audit_exceptions.each do |list_name, formula_names| - unless [Hash, Array].include? formula_names.class - problem <<~EOS - audit_exceptions/#{list_name}.json should contain a JSON array - of formula names or a JSON object mapping formula names to values - EOS - next - end - - formula_names = formula_names.keys if formula_names.is_a? Hash - - invalid_formulae = [] - formula_names.each do |name| - invalid_formulae << name if Formula[name].tap != @name - rescue FormulaUnavailableError - invalid_formulae << name - end - - next if invalid_formulae.empty? - - problem <<~EOS - audit_exceptions/#{list_name}.json references - formulae that are not found in the #{@name} tap. - Invalid formulae: #{invalid_formulae.join(", ")} - EOS - end - end - - def problem(message, location: nil) - @problems << ({ message: message, location: location }) - end - end end diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index 4f6d117609..946d0a912a 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -40,8 +40,11 @@ EOS MAXIMUM_STRING_MATCHES = 100 module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def bottle_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -437,22 +440,14 @@ module Homebrew if key == "cellar" # Prioritize HOMEBREW_CELLAR over :any over :any_skip_relocation cellars = [first, second] - if cellars.include?(HOMEBREW_CELLAR) - HOMEBREW_CELLAR - elsif first.start_with?("/") - first - elsif second.start_with?("/") - second - elsif cellars.include?("any") - "any" - elsif cellars.include?("any_skip_relocation") - "any_skip_relocation" - else - second - end - else - second + next HOMEBREW_CELLAR if cellars.include?(HOMEBREW_CELLAR) + next first if first.start_with?("/") + next second if second.start_with?("/") + next "any" if cellars.include?("any") + next "any_skip_relocation" if cellars.include?("any_skip_relocation") end + + second end end diff --git a/Library/Homebrew/dev-cmd/bump-cask-pr.rb b/Library/Homebrew/dev-cmd/bump-cask-pr.rb index a9ecedc589..032a8df0aa 100644 --- a/Library/Homebrew/dev-cmd/bump-cask-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-cask-pr.rb @@ -6,12 +6,15 @@ require "cli/parser" require "utils/tar" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def bump_cask_pr_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `bump-cask-pr` [] [] + `bump-cask-pr` [] Create a pull request to update with a new version. @@ -140,6 +143,7 @@ module Homebrew silent: true) tmp_cask = Cask::CaskLoader.load(tmp_contents) + tmp_config = cask.config tmp_url = tmp_cask.url.to_s if new_hash.nil? @@ -151,9 +155,9 @@ module Homebrew cask.languages.each do |language| next if language == cask.language - tmp_cask.config.languages = [language] - + lang_config = tmp_config.merge(Cask::Config.new(explicit: { languages: [language] })) lang_cask = Cask::CaskLoader.load(tmp_contents) + lang_cask.config = lang_config lang_url = lang_cask.url.to_s lang_old_hash = lang_cask.sha256 diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index dc4bb5a06b..4e648874f2 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -7,8 +7,11 @@ require "utils/pypi" require "utils/tar" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def bump_formula_pr_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -70,7 +73,7 @@ module Homebrew depends_on: "--tag=", description: "Specify the new git commit corresponding to the specified ." switch "-f", "--force", - description: "Ignore duplicate open PRs. Remove all mirrors if --mirror= was not specified." + description: "Ignore duplicate open PRs. Remove all mirrors if `--mirror` was not specified." conflicts "--dry-run", "--write" conflicts "--no-audit", "--strict" diff --git a/Library/Homebrew/dev-cmd/bump-revision.rb b/Library/Homebrew/dev-cmd/bump-revision.rb index aa53caaf47..745fef7717 100644 --- a/Library/Homebrew/dev-cmd/bump-revision.rb +++ b/Library/Homebrew/dev-cmd/bump-revision.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def bump_revision_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/bump.rb b/Library/Homebrew/dev-cmd/bump.rb index 543d751863..00f51e8870 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def bump_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -14,8 +17,8 @@ module Homebrew Display out-of-date brew formulae and the latest version available. Also displays whether a pull request has been opened with the URL. EOS - flag "--limit=", - description: "Limit number of package results returned." + flag "--limit=", + description: "Limit number of package results returned." switch :verbose switch :debug end diff --git a/Library/Homebrew/dev-cmd/cat.rb b/Library/Homebrew/dev-cmd/cat.rb index 3415e03e6e..3554694d60 100644 --- a/Library/Homebrew/dev-cmd/cat.rb +++ b/Library/Homebrew/dev-cmd/cat.rb @@ -4,22 +4,35 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def cat_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `cat` + `cat` | - Display the source of . + Display the source of a or . EOS - named :formula + + switch "--formula", "--formulae", + description: "Treat all named arguments as formulae." + switch "--cask", "--casks", + description: "Treat all named arguments as casks." + conflicts "--formula", "--cask" + + named :formula_or_cask end end def cat args = cat_args.parse + only = :formula if args.formula? && !args.cask? + only = :cask if args.cask? && !args.formula? + cd HOMEBREW_REPOSITORY pager = if Homebrew::EnvConfig.bat? ENV["BAT_CONFIG_PATH"] = Homebrew::EnvConfig.bat_config_path @@ -27,6 +40,7 @@ module Homebrew else "cat" end - safe_system pager, args.named.to_formulae_paths.first + + safe_system pager, args.named.to_paths(only: only).first end end diff --git a/Library/Homebrew/dev-cmd/command.rb b/Library/Homebrew/dev-cmd/command.rb index 7c2f6e37ce..9beb128138 100644 --- a/Library/Homebrew/dev-cmd/command.rb +++ b/Library/Homebrew/dev-cmd/command.rb @@ -5,8 +5,11 @@ require "commands" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def command_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index 177ba878e8..ea4b8a38a1 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -8,8 +8,11 @@ require "cli/parser" require "utils/pypi" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def create_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -56,7 +59,7 @@ module Homebrew flag "--tap=", description: "Generate the new formula within the given tap, specified as `/`." switch "-f", "--force", - description: "Ignore errors for disallowed formula names and named that shadow aliases." + description: "Ignore errors for disallowed formula names and names that shadow aliases." conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", "--perl", "--python", "--rust" named 1 diff --git a/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb b/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb index dc80f45fb4..fbb867e8ae 100644 --- a/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb +++ b/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb @@ -5,8 +5,11 @@ require "cli/parser" require "utils/github" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def dispatch_build_bottle_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -24,14 +27,14 @@ module Homebrew description: "Dispatch specified workflow (default: `dispatch-build-bottle.yml`)." switch "--upload", description: "Upload built bottles to Bintray." + + min_named :formula end end def dispatch_build_bottle args = dispatch_build_bottle_args.parse - raise FormulaUnspecifiedError if args.named.empty? - odie "Must specify --macos option" unless args.macos macos = begin diff --git a/Library/Homebrew/dev-cmd/diy.rb b/Library/Homebrew/dev-cmd/diy.rb index 31f57440c8..55696b2352 100644 --- a/Library/Homebrew/dev-cmd/diy.rb +++ b/Library/Homebrew/dev-cmd/diy.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def diy_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -28,6 +31,8 @@ module Homebrew def diy args = diy_args.parse + # odeprecated "`brew diy`" + path = Pathname.getwd version = args.version || detect_version(path) diff --git a/Library/Homebrew/dev-cmd/edit.rb b/Library/Homebrew/dev-cmd/edit.rb index f963aeb237..5526e9809e 100644 --- a/Library/Homebrew/dev-cmd/edit.rb +++ b/Library/Homebrew/dev-cmd/edit.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def edit_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb index 7bd9820d18..63f518f69f 100644 --- a/Library/Homebrew/dev-cmd/extract.rb +++ b/Library/Homebrew/dev-cmd/extract.rb @@ -76,8 +76,11 @@ ensure end module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def extract_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/formula.rb b/Library/Homebrew/dev-cmd/formula.rb index b5e7ccaec1..cee7263e9a 100644 --- a/Library/Homebrew/dev-cmd/formula.rb +++ b/Library/Homebrew/dev-cmd/formula.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def formula_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/install-bundler-gems.rb b/Library/Homebrew/dev-cmd/install-bundler-gems.rb index b15b49ee97..ce80576cb1 100644 --- a/Library/Homebrew/dev-cmd/install-bundler-gems.rb +++ b/Library/Homebrew/dev-cmd/install-bundler-gems.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def install_bundler_gems_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/irb.rb b/Library/Homebrew/dev-cmd/irb.rb index c5a0a29b8b..b5b09f9b1c 100644 --- a/Library/Homebrew/dev-cmd/irb.rb +++ b/Library/Homebrew/dev-cmd/irb.rb @@ -16,8 +16,11 @@ class String end module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def irb_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/linkage.rb b/Library/Homebrew/dev-cmd/linkage.rb index 631e9ec65b..4f161f8039 100644 --- a/Library/Homebrew/dev-cmd/linkage.rb +++ b/Library/Homebrew/dev-cmd/linkage.rb @@ -6,8 +6,11 @@ require "linkage_checker" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def linkage_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/livecheck.rb b/Library/Homebrew/dev-cmd/livecheck.rb index d177768026..2e6ab72334 100644 --- a/Library/Homebrew/dev-cmd/livecheck.rb +++ b/Library/Homebrew/dev-cmd/livecheck.rb @@ -7,6 +7,8 @@ require "livecheck/livecheck" require "livecheck/strategy" module Homebrew + extend T::Sig + module_function WATCHLIST_PATH = ( @@ -14,6 +16,7 @@ module Homebrew "#{Dir.home}/.brew_livecheck_watchlist" ).freeze + sig { returns(CLI::Parser) } def livecheck_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb index 0a17cdc96a..e32972af79 100644 --- a/Library/Homebrew/dev-cmd/man.rb +++ b/Library/Homebrew/dev-cmd/man.rb @@ -7,12 +7,15 @@ require "ostruct" require "cli/parser" module Homebrew + extend T::Sig + module_function SOURCE_PATH = (HOMEBREW_LIBRARY_PATH/"manpages").freeze TARGET_MAN_PATH = (HOMEBREW_REPOSITORY/"manpages").freeze TARGET_DOC_PATH = (HOMEBREW_REPOSITORY/"docs").freeze + sig { returns(CLI::Parser) } def man_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -27,6 +30,7 @@ module Homebrew "comparison without factoring in the date)." switch "--link", description: "This is now done automatically by `brew update`." + max_named 0 end end @@ -132,6 +136,8 @@ module Homebrew when "--markdown" ronn_output = ronn_output.gsub(%r{(.*?)}, "*`\\1`*") .gsub(/\n\n\n+/, "\n\n") + .gsub(/^(- `[^`]+`):/, "\\1") # drop trailing colons from definition lists + .gsub(/(?<=\n\n)([\[`].+):\n/, "\\1\n
") # replace colons with
on subcommands when "--roff" ronn_output = ronn_output.gsub(%r{(.*?)}, "\\fB\\1\\fR") .gsub(%r{(.*?)}, "\\fI\\1\\fR") @@ -210,14 +216,16 @@ module Homebrew lines end + sig { returns(String) } def global_cask_options_manpage lines = ["These options are applicable to subcommands accepting a `--cask` flag and all `cask` commands.\n"] lines += Homebrew::CLI::Parser.global_cask_options.map do |_, long, description:, **| - generate_option_doc(nil, long, description) + generate_option_doc(nil, long.chomp("="), description) end lines.join("\n") end + sig { returns(String) } def global_options_manpage lines = ["These options are applicable across multiple subcommands.\n"] lines += Homebrew::CLI::Parser.global_options.map do |short, long, desc| @@ -226,12 +234,13 @@ module Homebrew lines.join("\n") end + sig { returns(String) } def env_vars_manpage lines = Homebrew::EnvConfig::ENVS.flat_map do |env, hash| - entry = " * `#{env}`:\n #{hash[:description]}\n" + entry = "- `#{env}`:\n
#{hash[:description]}\n" default = hash[:default_text] default ||= "`#{hash[:default]}`." if hash[:default] - entry += "\n\n *Default:* #{default}\n" if default + entry += "\n\n *Default:* #{default}\n" if default entry end diff --git a/Library/Homebrew/dev-cmd/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb index 7790c32fed..a6c2b45b1a 100644 --- a/Library/Homebrew/dev-cmd/mirror.rb +++ b/Library/Homebrew/dev-cmd/mirror.rb @@ -5,8 +5,11 @@ require "bintray" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def mirror_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -21,8 +24,8 @@ module Homebrew switch "--no-publish", description: "Upload to Bintray, but don't publish." - hide_from_man_page! min_named :formula + hide_from_man_page! end end diff --git a/Library/Homebrew/dev-cmd/pr-automerge.rb b/Library/Homebrew/dev-cmd/pr-automerge.rb index 16634dd450..d4120ab4f4 100644 --- a/Library/Homebrew/dev-cmd/pr-automerge.rb +++ b/Library/Homebrew/dev-cmd/pr-automerge.rb @@ -5,8 +5,11 @@ require "cli/parser" require "utils/github" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def pr_automerge_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -18,9 +21,9 @@ module Homebrew description: "Target tap repository (default: `homebrew/core`)." flag "--with-label=", description: "Pull requests must have this label." - comma_array "--without-labels=", - description: "Pull requests must not have these labels "\ - "(default: `do not merge`, `new formula`, `automerge-skip`)." + comma_array "--without-labels", + description: "Pull requests must not have these labels (default: "\ + "`do not merge`, `new formula`, `automerge-skip`, `linux-only`)." switch "--without-approval", description: "Pull requests do not require approval to be merged." switch "--publish", @@ -38,7 +41,7 @@ module Homebrew def pr_automerge args = pr_automerge_args.parse - without_labels = args.without_labels || ["do not merge", "new formula", "automerge-skip"] + without_labels = args.without_labels || ["do not merge", "new formula", "automerge-skip", "linux-only"] tap = Tap.fetch(args.tap || CoreTap.instance.name) query = "is:pr is:open repo:#{tap.full_name}" diff --git a/Library/Homebrew/dev-cmd/pr-publish.rb b/Library/Homebrew/dev-cmd/pr-publish.rb index 86b675293b..de376b1cee 100644 --- a/Library/Homebrew/dev-cmd/pr-publish.rb +++ b/Library/Homebrew/dev-cmd/pr-publish.rb @@ -5,8 +5,11 @@ require "cli/parser" require "utils/github" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def pr_publish_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index a11704972f..010d3e6acc 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -8,8 +8,11 @@ require "tmpdir" require "formula" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def pr_pull_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -59,8 +62,9 @@ module Homebrew flag "--bintray-mirror=", description: "Use the specified Bintray repository to automatically mirror stable URLs "\ "defined in the formulae (default: `mirror`)." - min_named 1 + conflicts "--clean", "--autosquash" + min_named 1 end end @@ -282,8 +286,9 @@ module Homebrew Utils::Git.cherry_pick!(path, "--ff", "--allow-empty", *commits, verbose: args.verbose?, resolve: args.resolve?) end - def formulae_need_bottles?(tap, original_commit, args:) + def formulae_need_bottles?(tap, original_commit, user, repo, pr, args:) return if args.dry_run? + return false if GitHub.pull_request_labels(user, repo, pr).include? "CI-syntax-only" changed_formulae(tap, original_commit).any? do |f| !f.bottle_unneeded? && !f.bottle_disabled? @@ -391,7 +396,7 @@ module Homebrew args: args) end - unless formulae_need_bottles?(tap, original_commit, args: args) + unless formulae_need_bottles?(tap, original_commit, user, repo, pr, args: args) ohai "Skipping artifacts for ##{pr} as the formulae don't need bottles" next end @@ -418,6 +423,8 @@ module Homebrew end class GitHubArtifactDownloadStrategy < AbstractFileDownloadStrategy + extend T::Sig + def fetch ohai "Downloading #{url}" if cached_location.exist? @@ -441,6 +448,7 @@ class GitHubArtifactDownloadStrategy < AbstractFileDownloadStrategy private + sig { returns(String) } def resolved_basename "artifact.zip" end diff --git a/Library/Homebrew/dev-cmd/pr-upload.rb b/Library/Homebrew/dev-cmd/pr-upload.rb index 23ed9e9cef..d26a6c0cfe 100644 --- a/Library/Homebrew/dev-cmd/pr-upload.rb +++ b/Library/Homebrew/dev-cmd/pr-upload.rb @@ -5,8 +5,11 @@ require "cli/parser" require "bintray" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def pr_upload_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/prof.rb b/Library/Homebrew/dev-cmd/prof.rb index 2c40d0b7fc..add6a5ae01 100644 --- a/Library/Homebrew/dev-cmd/prof.rb +++ b/Library/Homebrew/dev-cmd/prof.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def prof_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb index ce279b1f80..ce6f69c358 100644 --- a/Library/Homebrew/dev-cmd/pull.rb +++ b/Library/Homebrew/dev-cmd/pull.rb @@ -12,11 +12,13 @@ require "pkg_version" require "formula_info" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def pull_args Homebrew::CLI::Parser.new do - hide_from_man_page! usage_banner <<~EOS `pull` [] @@ -40,6 +42,7 @@ module Homebrew description: "Do not copy anything to the system clipboard." min_named 1 + hide_from_man_page! end end diff --git a/Library/Homebrew/dev-cmd/release-notes.rb b/Library/Homebrew/dev-cmd/release-notes.rb index 7288d85e12..3e7286cdc4 100644 --- a/Library/Homebrew/dev-cmd/release-notes.rb +++ b/Library/Homebrew/dev-cmd/release-notes.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def release_notes_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -17,6 +20,7 @@ module Homebrew EOS switch "--markdown", description: "Print as a Markdown list." + max_named 2 end end diff --git a/Library/Homebrew/dev-cmd/ruby.rb b/Library/Homebrew/dev-cmd/ruby.rb index 4e4f014d08..47475f39e3 100644 --- a/Library/Homebrew/dev-cmd/ruby.rb +++ b/Library/Homebrew/dev-cmd/ruby.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def ruby_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/sh.rb b/Library/Homebrew/dev-cmd/sh.rb index a1f35adc14..3c56c13dd0 100644 --- a/Library/Homebrew/dev-cmd/sh.rb +++ b/Library/Homebrew/dev-cmd/sh.rb @@ -6,8 +6,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def sh_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -23,6 +26,7 @@ module Homebrew description: "Use the standard `PATH` instead of superenv's when `std` is passed." flag "-c=", "--cmd=", description: "Execute commands in a non-interactive shell." + max_named 1 end end diff --git a/Library/Homebrew/dev-cmd/sponsors.rb b/Library/Homebrew/dev-cmd/sponsors.rb index 0e3bece7d2..b6d03a839d 100644 --- a/Library/Homebrew/dev-cmd/sponsors.rb +++ b/Library/Homebrew/dev-cmd/sponsors.rb @@ -5,8 +5,11 @@ require "cli/parser" require "utils/github" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def sponsors_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/style.rb b/Library/Homebrew/dev-cmd/style.rb index 8b3d5439a2..611ab05ce0 100644 --- a/Library/Homebrew/dev-cmd/style.rb +++ b/Library/Homebrew/dev-cmd/style.rb @@ -7,8 +7,11 @@ require "style" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def style_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index d9c9f3b5e8..fb63340591 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -5,8 +5,11 @@ require "tap" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def tap_new_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -16,11 +19,11 @@ module Homebrew EOS switch "--no-git", - description: "Don't initialize a git repository for the tap." + description: "Don't initialize a Git repository for the tap." flag "--pull-label=", - description: "Label name for pull requests ready to be pulled (default `pr-pull`)." + description: "Label name for pull requests ready to be pulled (default: `pr-pull`)." flag "--branch=", - description: "Initialize git repository with the specified branch name (default `main`)." + description: "Initialize Git repository with the specified branch name (default: `main`)." conflicts "--no-git", "--branch" named 1 diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb index 087f5f5510..8933ec8ae1 100644 --- a/Library/Homebrew/dev-cmd/test.rb +++ b/Library/Homebrew/dev-cmd/test.rb @@ -7,8 +7,11 @@ require "timeout" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def test_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index 428177807e..a6f54d9d60 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -5,8 +5,11 @@ require "cli/parser" require "fileutils" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def tests_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -55,6 +58,7 @@ module Homebrew ENV.delete("HOMEBREW_NO_EMOJI") ENV.delete("HOMEBREW_DEVELOPER") ENV.delete("HOMEBREW_PRY") + ENV.delete("HOMEBREW_BAT") ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1" ENV["HOMEBREW_NO_COMPAT"] = "1" if args.no_compat? ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if args.generic? diff --git a/Library/Homebrew/dev-cmd/typecheck.rb b/Library/Homebrew/dev-cmd/typecheck.rb index c8c45fa88b..454715b098 100644 --- a/Library/Homebrew/dev-cmd/typecheck.rb +++ b/Library/Homebrew/dev-cmd/typecheck.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def typecheck_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -13,6 +16,8 @@ module Homebrew Check for typechecking errors using Sorbet. EOS + switch "--fix", + description: "Automatically fix type errors." switch "-q", "--quiet", description: "Silence all non-critical errors." switch "--update", @@ -27,6 +32,7 @@ module Homebrew flag "--ignore=", description: "Ignores input files that contain the given string " \ "in their paths (relative to the input path passed to Sorbet)." + conflicts "--dir", "--file" max_named 0 end @@ -51,6 +57,7 @@ module Homebrew srb_exec = %w[bundle exec srb tc] srb_exec << "--quiet" if args.quiet? + srb_exec << "--autocorrect" if args.fix? srb_exec += ["--ignore", args.ignore] if args.ignore.present? if args.file.present? || args.dir.present? cd("sorbet") diff --git a/Library/Homebrew/dev-cmd/unpack.rb b/Library/Homebrew/dev-cmd/unpack.rb index e88b9ef2cc..529bfcc046 100644 --- a/Library/Homebrew/dev-cmd/unpack.rb +++ b/Library/Homebrew/dev-cmd/unpack.rb @@ -6,8 +6,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def unpack_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/update-license-data.rb b/Library/Homebrew/dev-cmd/update-license-data.rb index 6d11bca358..c41c6ace7f 100644 --- a/Library/Homebrew/dev-cmd/update-license-data.rb +++ b/Library/Homebrew/dev-cmd/update-license-data.rb @@ -5,8 +5,11 @@ require "cli/parser" require "utils/spdx" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def update_license_data_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -17,6 +20,7 @@ module Homebrew switch "--fail-if-not-changed", description: "Return a failing status code if current license data's version is the same as " \ "the upstream. This can be used to notify CI when the SPDX license data is out of date." + max_named 0 end end diff --git a/Library/Homebrew/dev-cmd/update-python-resources.rb b/Library/Homebrew/dev-cmd/update-python-resources.rb index e109887bbc..ee3cd4be19 100644 --- a/Library/Homebrew/dev-cmd/update-python-resources.rb +++ b/Library/Homebrew/dev-cmd/update-python-resources.rb @@ -5,8 +5,11 @@ require "cli/parser" require "utils/pypi" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def update_python_resources_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -20,9 +23,10 @@ module Homebrew description: "Suppress any output." switch "--ignore-non-pypi-packages", description: "Don't fail if is not a PyPI package." - flag "--version=", - description: "Use the specified when finding resources for . "\ - "If no version is specified, the current version for will be used." + flag "--version=", + description: "Use the specified when finding resources for . "\ + "If no version is specified, the current version for will be used." + min_named :formula end end diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index f6c3adce43..789ec21aa9 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -4,8 +4,11 @@ require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def update_test_args Homebrew::CLI::Parser.new do usage_banner <<~EOS diff --git a/Library/Homebrew/dev-cmd/vendor-gems.rb b/Library/Homebrew/dev-cmd/vendor-gems.rb index f42945f2b2..9ff4e6ed52 100644 --- a/Library/Homebrew/dev-cmd/vendor-gems.rb +++ b/Library/Homebrew/dev-cmd/vendor-gems.rb @@ -5,8 +5,11 @@ require "formula" require "cli/parser" module Homebrew + extend T::Sig + module_function + sig { returns(CLI::Parser) } def vendor_gems_args Homebrew::CLI::Parser.new do usage_banner <<~EOS @@ -15,17 +18,28 @@ module Homebrew Install and commit Homebrew's vendored gems. EOS + switch "--update", + description: "Update all vendored Gems to the latest version." + max_named 0 end end def vendor_gems - vendor_gems_args.parse + args = vendor_gems_args.parse Homebrew.install_bundler! ohai "cd #{HOMEBREW_LIBRARY_PATH}" HOMEBREW_LIBRARY_PATH.cd do + if args.update? + ohai "bundle update" + safe_system "bundle", "update" + + ohai "git add Gemfile.lock" + system "git", "add", "Gemfile.lock" + end + ohai "bundle install --standalone" safe_system "bundle", "install", "--standalone" diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 0964ca0be1..9a83aaafd0 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -48,6 +48,8 @@ module Homebrew # Diagnostic checks. class Checks + extend T::Sig + def initialize(verbose: true) @verbose = verbose end @@ -71,6 +73,7 @@ module Homebrew path.gsub(ENV["HOME"], "~") end + sig { returns(String) } def none_string "" end @@ -112,8 +115,8 @@ module Homebrew <<~EOS You will encounter build failures with some formulae. Please create pull requests instead of asking for help on Homebrew's GitHub, - Discourse, Twitter or any other official channels. You are responsible for - resolving any issues you experience while you are running this + Twitter or any other official channels. You are responsible for resolving + any issues you experience while you are running this #{what}. EOS end diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index d7a2b69f50..81dcf445fc 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -17,6 +17,8 @@ require "utils/curl" # # @api private class AbstractDownloadStrategy + extend T::Sig + extend Forwardable include FileUtils include Context @@ -55,6 +57,7 @@ class AbstractDownloadStrategy # TODO: Deprecate once we have an explicitly documented alternative. # # @api public + sig { void } def shutup! @quiet = true end @@ -586,6 +589,8 @@ end # # @api public class SubversionDownloadStrategy < VCSDownloadStrategy + extend T::Sig + def initialize(url, name, version, **meta) super @url = @url.sub("svn+http://", "") @@ -602,6 +607,7 @@ class SubversionDownloadStrategy < VCSDownloadStrategy end # (see AbstractDownloadStrategy#source_modified_time) + sig { returns(Time) } def source_modified_time time = if Version.create(Utils::Svn.version) >= Version.create("1.9") out, = silent_command("svn", args: ["info", "--show-item", "last-changed-date"], chdir: cached_location) @@ -660,6 +666,7 @@ class SubversionDownloadStrategy < VCSDownloadStrategy end end + sig { returns(String) } def cache_tag head? ? "svn-HEAD" : "svn" end @@ -706,6 +713,7 @@ class GitDownloadStrategy < VCSDownloadStrategy end # (see AbstractDownloadStrategy#source_modified_time) + sig { returns(Time) } def source_modified_time out, = silent_command("git", args: ["--git-dir", git_dir, "show", "-s", "--format=%cD"]) Time.parse(out) @@ -719,10 +727,12 @@ class GitDownloadStrategy < VCSDownloadStrategy private + sig { returns(String) } def cache_tag "git" end + sig { returns(Integer) } def cache_version 0 end @@ -770,6 +780,7 @@ class GitDownloadStrategy < VCSDownloadStrategy (cached_location/".gitmodules").exist? end + sig { returns(T::Array[String]) } def clone_args args = %w[clone] args << "--depth" << "1" if shallow_clone? @@ -783,6 +794,7 @@ class GitDownloadStrategy < VCSDownloadStrategy args << @url << cached_location end + sig { returns(String) } def refspec case @ref_type when :branch then "+refs/heads/#{@ref}:refs/remotes/origin/#{@ref}" @@ -953,6 +965,8 @@ end # # @api public class CVSDownloadStrategy < VCSDownloadStrategy + extend T::Sig + def initialize(url, name, version, **meta) super @url = @url.sub(%r{^cvs://}, "") @@ -967,6 +981,7 @@ class CVSDownloadStrategy < VCSDownloadStrategy end # (see AbstractDownloadStrategy#source_modified_time) + sig { returns(Time) } def source_modified_time # Filter CVS's files because the timestamp for each of them is the moment # of clone. @@ -987,6 +1002,7 @@ class CVSDownloadStrategy < VCSDownloadStrategy { "PATH" => PATH.new("/usr/bin", Formula["cvs"].opt_bin, ENV["PATH"]) } end + sig { returns(String) } def cache_tag "cvs" end @@ -1026,12 +1042,15 @@ end # # @api public class MercurialDownloadStrategy < VCSDownloadStrategy + extend T::Sig + def initialize(url, name, version, **meta) super @url = @url.sub(%r{^hg://}, "") end # (see AbstractDownloadStrategy#source_modified_time) + sig { returns(Time) } def source_modified_time out, = silent_command("hg", args: ["tip", "--template", "{date|isodate}", "-R", cached_location]) @@ -1051,6 +1070,7 @@ class MercurialDownloadStrategy < VCSDownloadStrategy { "PATH" => PATH.new(Formula["mercurial"].opt_bin, ENV["PATH"]) } end + sig { returns(String) } def cache_tag "hg" end @@ -1081,12 +1101,15 @@ end # # @api public class BazaarDownloadStrategy < VCSDownloadStrategy + extend T::Sig + def initialize(url, name, version, **meta) super @url.sub!(%r{^bzr://}, "") end # (see AbstractDownloadStrategy#source_modified_time) + sig { returns(Time) } def source_modified_time out, = silent_command("bzr", args: ["log", "-l", "1", "--timezone=utc", cached_location]) timestamp = out.chomp @@ -1110,6 +1133,7 @@ class BazaarDownloadStrategy < VCSDownloadStrategy } end + sig { returns(String) } def cache_tag "bzr" end @@ -1135,12 +1159,15 @@ end # # @api public class FossilDownloadStrategy < VCSDownloadStrategy + extend T::Sig + def initialize(url, name, version, **meta) super @url = @url.sub(%r{^fossil://}, "") end # (see AbstractDownloadStrategy#source_modified_time) + sig { returns(Time) } def source_modified_time out, = silent_command("fossil", args: ["info", "tip", "-R", cached_location]) Time.parse(out[/^uuid: +\h+ (.+)$/, 1]) @@ -1162,6 +1189,7 @@ class FossilDownloadStrategy < VCSDownloadStrategy { "PATH" => PATH.new(Formula["fossil"].opt_bin, ENV["PATH"]) } end + sig { returns(String) } def cache_tag "fossil" end @@ -1205,22 +1233,20 @@ class DownloadStrategyDetector when %r{^https?://(.+?\.)?googlecode\.com/svn}, %r{^https?://svn\.}, %r{^svn://}, + %r{^svn\+http://}, + %r{^http://svn\.apache\.org/repos/}, %r{^https?://(.+?\.)?sourceforge\.net/svnroot/} SubversionDownloadStrategy when %r{^cvs://} CVSDownloadStrategy when %r{^hg://}, - %r{^https?://(.+?\.)?googlecode\.com/hg} + %r{^https?://(.+?\.)?googlecode\.com/hg}, + %r{^https?://(.+?\.)?sourceforge\.net/hgweb/} MercurialDownloadStrategy when %r{^bzr://} BazaarDownloadStrategy when %r{^fossil://} FossilDownloadStrategy - when %r{^svn\+http://}, - %r{^http://svn\.apache\.org/repos/} - SubversionDownloadStrategy - when %r{^https?://(.+?\.)?sourceforge\.net/hgweb/} - MercurialDownloadStrategy else CurlDownloadStrategy end diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index 278cd0f3e9..713c460222 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -6,11 +6,13 @@ module Homebrew # # @api private module EnvConfig + extend T::Sig + module_function ENVS = { HOMEBREW_ARCH: { - description: "Linux only: Pass the set value to a type name representing the compiler's `-march` option.", + description: "Linux only: Pass this value to a type name representing the compiler's `-march` option.", default: "native", }, HOMEBREW_ARTIFACT_DOMAIN: { @@ -28,8 +30,8 @@ module Homebrew boolean: true, }, HOMEBREW_BAT_CONFIG_PATH: { - description: "Use the `bat` configuration file. For example, `HOMEBREW_BAT=$HOME/.bat/config`.", - default_text: "$HOME/.bat/config", + description: "Use this as the `bat` configuration file.", + default_text: "`$HOME/.bat/config`.", }, HOMEBREW_BINTRAY_KEY: { description: "Use this API key when accessing the Bintray API (where bottles are stored).", @@ -38,14 +40,15 @@ module Homebrew description: "Use this username when accessing the Bintray API (where bottles are stored).", }, HOMEBREW_BOTTLE_DOMAIN: { - description: "Use the specified URL as the download mirror for bottles. " \ - "For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to " \ - "download from the prefix `http://localhost:8080/`.", - default_text: "macOS: `https://homebrew.bintray.com/`, Linux: `https://linuxbrew.bintray.com/`.", + description: "Use this URL as the download mirror for bottles. " \ + "For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to " \ + "download from the prefix `http://localhost:8080/`.", + default_text: "macOS: `https://homebrew.bintray.com/`, " \ + "Linux: `https://linuxbrew.bintray.com/`.", default: HOMEBREW_BOTTLE_DEFAULT_DOMAIN, }, HOMEBREW_BREW_GIT_REMOTE: { - description: "Use the specified URL as the Homebrew/brew `git`(1) remote.", + description: "Use this URL as the Homebrew/brew `git`(1) remote.", default: HOMEBREW_BREW_DEFAULT_GIT_REMOTE, }, HOMEBREW_BROWSER: { @@ -53,18 +56,17 @@ module Homebrew default_text: "`$BROWSER` or the OS's default browser.", }, HOMEBREW_CACHE: { - description: "Use the specified directory as the download cache.", + description: "Use this directory as the download cache.", default_text: "macOS: `$HOME/Library/Caches/Homebrew`, " \ "Linux: `$XDG_CACHE_HOME/Homebrew` or `$HOME/.cache/Homebrew`.", default: HOMEBREW_DEFAULT_CACHE, }, HOMEBREW_CASK_OPTS: { - description: "Options which should be used for all `cask` commands. All `--*dir` options, " \ - "`--language`, `--require-sha`, `--no-quarantine` and `--no-binaries` are supported." \ - "\n" \ + description: "Append these options to all `cask` commands. All `--*dir` options, " \ + "`--language`, `--require-sha`, `--no-quarantine` and `--no-binaries` are supported. " \ "For example, you might add something like the following to your " \ - "~/.profile, ~/.bash_profile, or ~/.zshenv:\n\n" \ - "`export HOMEBREW_CASK_OPTS='--appdir=~/Applications --fontdir=/Library/Fonts'`", + "`~/.profile`, `~/.bash_profile`, or `~/.zshenv`:\n\n" \ + ' `export HOMEBREW_CASK_OPTS="--appdir=~/Applications --fontdir=/Library/Fonts"`', }, HOMEBREW_CLEANUP_MAX_AGE_DAYS: { description: "Cleanup all cached files older than this many days.", @@ -75,7 +77,7 @@ module Homebrew boolean: true, }, HOMEBREW_CORE_GIT_REMOTE: { - description: "Use the specified URL as the Homebrew/homebrew-core `git`(1) remote.", + description: "Use this URL as the Homebrew/homebrew-core `git`(1) remote.", default_text: "macOS: `https://github.com/Homebrew/homebrew-core`, " \ "Linux: `https://github.com/Homebrew/linuxbrew-core`.", default: HOMEBREW_CORE_DEFAULT_GIT_REMOTE, @@ -105,7 +107,7 @@ module Homebrew }, HOMEBREW_DISPLAY: { description: "Use this X11 display when opening a page in a browser, for example with " \ - "`brew home`. Primarily useful on Linux.", + "`brew home`. Primarily useful on Linux.", default_text: "`$DISPLAY`.", }, HOMEBREW_DISPLAY_INSTALL_TIMES: { @@ -114,9 +116,10 @@ module Homebrew }, HOMEBREW_EDITOR: { description: "Use this editor when editing a single formula, or several formulae in the " \ - "same directory.\n\n *Note:* `brew edit` will open all of Homebrew as discontinuous files " \ - "and directories. Visual Studio Code can handle this correctly in project mode, but many " \ - "editors will do strange things in this case.", + "same directory." \ + "\n\n *Note:* `brew edit` will open all of Homebrew as discontinuous files " \ + "and directories. Visual Studio Code can handle this correctly in project mode, but many " \ + "editors will do strange things in this case.", default_text: "`$EDITOR` or `$VISUAL`.", }, HOMEBREW_FAIL_LOG_LINES: { @@ -125,7 +128,7 @@ module Homebrew }, HOMEBREW_FORBIDDEN_LICENSES: { description: "A space-separated list of licenses. Homebrew will refuse to install a " \ - "formula if that formula or any of its dependencies has a license on this list.", + "formula if it or any of its dependencies has a license on this list.", }, HOMEBREW_FORCE_BREWED_CURL: { description: "If set, always use a Homebrew-installed `curl`(1) rather than the system version. " \ @@ -155,19 +158,19 @@ module Homebrew description: "Use this personal access token for the GitHub API, for features such as " \ "`brew search`. You can create one at . If set, " \ "GitHub will allow you a greater number of API requests. For more information, see: " \ - ".\n\n" \ - " *Note:* Homebrew doesn't require permissions for any of the scopes, but some developer " \ - "commands may require additional permissions.", + "" \ + "\n\n *Note:* Homebrew doesn't require permissions for any of the scopes, but some " \ + "developer commands may require additional permissions.", }, HOMEBREW_GITHUB_API_USERNAME: { description: "Use this username for authentication with the GitHub API, for features " \ "such as `brew search`. This is deprecated in favour of using `HOMEBREW_GITHUB_API_TOKEN`.", }, HOMEBREW_GIT_EMAIL: { - description: "Set the Git author and committer name to this value.", + description: "Set the Git author and committer email to this value.", }, HOMEBREW_GIT_NAME: { - description: "Set the Git author and committer email to this value.", + description: "Set the Git author and committer name to this value.", }, HOMEBREW_INSTALL_BADGE: { description: "Print this text before the installation summary of each successful build.", @@ -175,13 +178,13 @@ module Homebrew default: "🍺", }, HOMEBREW_LIVECHECK_WATCHLIST: { - description: "Use this file to get the list of default Formulae to check when no Formula argument " \ - "is passed to `brew livecheck`", + description: "Consult this file for the list of formulae to check by default when no formula argument " \ + "is passed to `brew livecheck`.", default: "$HOME/.brew_livecheck_watchlist", }, HOMEBREW_LOGS: { - description: "Use the specified directory to store log files.", - default_text: "macOS: `$HOME/Library/Logs/Homebrew`, "\ + description: "Use this directory to store log files.", + default_text: "macOS: `$HOME/Library/Logs/Homebrew`, " \ "Linux: `$XDG_CACHE_HOME/Homebrew/Logs` or `$HOME/.cache/Homebrew/Logs`.", default: HOMEBREW_DEFAULT_LOGS, }, @@ -195,7 +198,7 @@ module Homebrew }, }, HOMEBREW_NO_ANALYTICS: { - description: "If set, do not send analytics. See: .", + description: "If set, do not send analytics. For more information, see: ", boolean: true, }, HOMEBREW_NO_AUTO_UPDATE: { @@ -224,18 +227,18 @@ module Homebrew }, HOMEBREW_NO_EMOJI: { description: "If set, do not print `HOMEBREW_INSTALL_BADGE` on a successful build." \ - "\n\n *Note:* Only tries to print emoji on OS X Lion or newer.", + "\n\n *Note:* Will only try to print emoji on OS X Lion or newer.", boolean: true, }, HOMEBREW_NO_GITHUB_API: { description: "If set, do not use the GitHub API, e.g. for searches or fetching relevant issues " \ - "on a failed install.", + "after a failed install.", boolean: true, }, HOMEBREW_NO_INSECURE_REDIRECT: { description: "If set, forbid redirects from secure HTTPS to insecure HTTP." \ "\n\n *Note:* While ensuring your downloads are fully secure, this is likely to cause " \ - "from-source SourceForge, some GNU & GNOME based formulae to fail to download.", + "from-source SourceForge, some GNU & GNOME-hosted formulae to fail to download.", boolean: true, }, HOMEBREW_NO_INSTALL_CLEANUP: { @@ -248,12 +251,12 @@ module Homebrew boolean: true, }, HOMEBREW_SKIP_OR_LATER_BOTTLES: { - description: "If set with `HOMEBREW_DEVELOPER`, do not use bottles from older versions " \ + description: "If set along with `HOMEBREW_DEVELOPER`, do not use bottles from older versions " \ "of macOS. This is useful in development on new macOS versions.", boolean: true, }, HOMEBREW_SORBET_RUNTIME: { - description: "Enable runtime typechecking using Sorbet.", + description: "If set, enable runtime typechecking using Sorbet.", boolean: true, }, HOMEBREW_SVN: { @@ -270,7 +273,7 @@ module Homebrew default: HOMEBREW_DEFAULT_TEMP, }, HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED: { - description: "If set, `brew update` only outputs updates to installed software.", + description: "If set, `brew update` only lists updates to installed software.", boolean: true, }, HOMEBREW_UPDATE_TO_TAG: { @@ -308,7 +311,7 @@ module Homebrew "from proxying by `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew.", }, SUDO_ASKPASS: { - description: "When this variable is set, the `-A` option is passed when calling `sudo`(8)", + description: "If set, pass the `-A` option when calling `sudo`(8).", }, }.freeze @@ -358,10 +361,12 @@ module Homebrew .to_s end + sig { returns(T::Array[String]) } def cask_opts Shellwords.shellsplit(ENV.fetch("HOMEBREW_CASK_OPTS", "")) end + sig { returns(T::Boolean) } def cask_opts_binaries? cask_opts.reverse_each do |opt| return true if opt == "--binaries" @@ -371,6 +376,7 @@ module Homebrew true end + sig { returns(T::Boolean) } def cask_opts_quarantine? cask_opts.reverse_each do |opt| return true if opt == "--quarantine" @@ -380,6 +386,7 @@ module Homebrew true end + sig { returns(T::Boolean) } def cask_opts_require_sha? cask_opts.include?("--require-sha") end diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index f48dfed104..fadca48894 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -6,6 +6,8 @@ require "utils" # Raised when a command is used wrong. class UsageError < RuntimeError + extend T::Sig + attr_reader :reason def initialize(reason = nil) @@ -14,6 +16,7 @@ class UsageError < RuntimeError @reason = reason end + sig { returns(String) } def to_s s = "Invalid usage" s += ": #{reason}" if reason @@ -78,6 +81,8 @@ end # Raised when neither a formula nor a cask with the given name is available. class FormulaOrCaskUnavailableError < RuntimeError + extend T::Sig + attr_reader :name def initialize(name) @@ -86,6 +91,7 @@ class FormulaOrCaskUnavailableError < RuntimeError @name = name end + sig { returns(String) } def to_s "No available formula or cask with the name \"#{name}\"." end @@ -93,14 +99,18 @@ end # Raised when a formula is not available. class FormulaUnavailableError < FormulaOrCaskUnavailableError + extend T::Sig + attr_accessor :dependent + sig { returns(T.nilable(String)) } def dependent_s - "(dependency of #{dependent})" if dependent && dependent != name + " (dependency of #{dependent})" if dependent && dependent != name end + sig { returns(String) } def to_s - "No available formula with the name \"#{name}\" #{dependent_s}" + "No available formula with the name \"#{name}\"#{dependent_s}." end end @@ -108,6 +118,8 @@ end # # @api private module FormulaClassUnavailableErrorModule + extend T::Sig + attr_reader :path, :class_name, :class_list def to_s @@ -119,6 +131,7 @@ module FormulaClassUnavailableErrorModule private + sig { returns(String) } def class_list_s formula_class_list = class_list.select { |klass| klass < Formula } if class_list.empty? @@ -151,8 +164,11 @@ end # # @api private module FormulaUnreadableErrorModule + extend T::Sig + attr_reader :formula_error + sig { returns(String) } def to_s "#{name}: " + formula_error.to_s end @@ -327,6 +343,8 @@ end # Raised when a formula conflicts with another one. class FormulaConflictError < RuntimeError + extend T::Sig + attr_reader :formula, :conflicts def initialize(formula, conflicts) @@ -342,6 +360,7 @@ class FormulaConflictError < RuntimeError message.join end + sig { returns(String) } def message message = [] message << "Cannot install #{formula.full_name} because conflicting formulae are installed." @@ -549,6 +568,8 @@ end # Raised by {Kernel#safe_system} in `utils.rb`. class ErrorDuringExecution < RuntimeError + extend T::Sig + attr_reader :cmd, :status, :output def initialize(cmd, status:, output: nil, secrets: []) @@ -583,6 +604,7 @@ class ErrorDuringExecution < RuntimeError super s.freeze end + sig { returns(String) } def stderr Array(output).select { |type,| type == :stderr }.map(&:last).join end diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index 30dfaeef20..bea1efc156 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -6,6 +6,8 @@ require "extend/ENV/shared" # @private module Stdenv + extend T::Sig + include SharedEnvExtension # @private @@ -58,6 +60,7 @@ module Stdenv [] end + sig { returns(T.nilable(PATH)) } def determine_pkg_config_libdir PATH.new( HOMEBREW_PREFIX/"lib/pkgconfig", diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 966e5e7c87..4b1ba40b84 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -15,6 +15,8 @@ require "development_tools" # 7. Simpler formulae that *just work* # 8. Build-system agnostic configuration of the toolchain module Superenv + extend T::Sig + include SharedEnvExtension # @private @@ -103,6 +105,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_path path = PATH.new(Superenv.bin) @@ -125,6 +128,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_pkg_config_path PATH.new( deps.map { |d| d.opt_lib/"pkgconfig" }, @@ -132,6 +136,7 @@ module Superenv ).existing end + sig { returns(T.nilable(PATH)) } def determine_pkg_config_libdir PATH.new( homebrew_extra_pkg_config_paths, @@ -142,6 +147,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_aclocal_path PATH.new( keg_only_deps.map { |d| d.opt_share/"aclocal" }, @@ -154,6 +160,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_isystem_paths PATH.new( HOMEBREW_PREFIX/"include", @@ -161,6 +168,7 @@ module Superenv ).existing end + sig { returns(T.nilable(PATH)) } def determine_include_paths PATH.new(keg_only_deps.map(&:opt_include)).existing end @@ -169,6 +177,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_library_paths paths = [ keg_only_deps.map(&:opt_lib), @@ -182,6 +191,7 @@ module Superenv deps.map(&:name).join(",") end + sig { returns(T.nilable(PATH)) } def determine_cmake_prefix_path PATH.new( keg_only_deps.map(&:opt_prefix), @@ -193,6 +203,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_cmake_include_path PATH.new(homebrew_extra_cmake_include_paths).existing end @@ -201,6 +212,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_cmake_library_path PATH.new(homebrew_extra_cmake_library_paths).existing end @@ -209,6 +221,7 @@ module Superenv [] end + sig { returns(T.nilable(PATH)) } def determine_cmake_frameworks_path PATH.new( deps.map(&:opt_frameworks), diff --git a/Library/Homebrew/extend/os/linux/development_tools.rb b/Library/Homebrew/extend/os/linux/development_tools.rb index 4e3bc56c9e..e1120688eb 100644 --- a/Library/Homebrew/extend/os/linux/development_tools.rb +++ b/Library/Homebrew/extend/os/linux/development_tools.rb @@ -3,6 +3,8 @@ class DevelopmentTools class << self + extend T::Sig + def locate(tool) (@locate ||= {}).fetch(tool) do |key| @locate[key] = if (path = HOMEBREW_PREFIX/"bin/#{tool}").executable? @@ -13,6 +15,7 @@ class DevelopmentTools end end + sig { returns(Symbol) } def default_compiler :gcc end diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb index a3fda016ef..ebf600ad0d 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb @@ -2,6 +2,8 @@ # frozen_string_literal: true module Superenv + extend T::Sig + # @private def self.bin (HOMEBREW_SHIMS_PATH/"linux/super").realpath @@ -34,6 +36,7 @@ module Superenv ) end + sig { returns(T.nilable(String)) } def determine_dynamic_linker_path path = "#{HOMEBREW_PREFIX}/lib/ld.so" return unless File.readable? path diff --git a/Library/Homebrew/extend/os/linux/formula.rb b/Library/Homebrew/extend/os/linux/formula.rb index fdcecb20d2..29ff3dd802 100644 --- a/Library/Homebrew/extend/os/linux/formula.rb +++ b/Library/Homebrew/extend/os/linux/formula.rb @@ -4,8 +4,8 @@ class Formula undef on_linux - def on_linux(&_block) - raise "No block content defined for on_linux block" unless block_given? + def on_linux(&block) + raise "No block content defined for on_linux block" unless block yield end @@ -19,8 +19,8 @@ class Formula class << self undef on_linux - def on_linux(&_block) - raise "No block content defined for on_linux block" unless block_given? + def on_linux(&block) + raise "No block content defined for on_linux block" unless block yield end diff --git a/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb index 1f4d2ce132..05a764d10c 100644 --- a/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb +++ b/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb @@ -4,6 +4,8 @@ require "requirement" class OsxfuseRequirement < Requirement + extend T::Sig + download "https://github.com/libfuse/libfuse" satisfy(build_env: false) do @@ -20,6 +22,7 @@ class OsxfuseRequirement < Requirement false end + sig { returns(String) } def message msg = "libfuse is required for this software.\n" if libfuse_formula_exists? @@ -33,6 +36,7 @@ class OsxfuseRequirement < Requirement private + sig { returns(T::Boolean) } def libfuse_formula_exists? begin Formula["libfuse"] diff --git a/Library/Homebrew/extend/os/mac/development_tools.rb b/Library/Homebrew/extend/os/mac/development_tools.rb index 15ea337b26..f101a31056 100644 --- a/Library/Homebrew/extend/os/mac/development_tools.rb +++ b/Library/Homebrew/extend/os/mac/development_tools.rb @@ -6,6 +6,8 @@ require "os/mac/xcode" # @private class DevelopmentTools class << self + extend T::Sig + alias generic_locate locate undef installed?, default_compiler, curl_handles_most_https_certificates?, subversion_handles_most_https_certificates? @@ -28,22 +30,26 @@ class DevelopmentTools MacOS::Xcode.installed? || MacOS::CLT.installed? end + sig { returns(Symbol) } def default_compiler :clang end + sig { returns(T::Boolean) } def curl_handles_most_https_certificates? # The system Curl is too old for some modern HTTPS certificates on # older macOS versions. ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil? end + sig { returns(T::Boolean) } def subversion_handles_most_https_certificates? # The system Subversion is too old for some HTTPS certificates on # older macOS versions. MacOS.version >= :sierra end + sig { returns(String) } def installation_instructions <<~EOS Install the Command Line Tools: @@ -51,6 +57,7 @@ class DevelopmentTools EOS end + sig { returns(String) } def custom_installation_instructions <<~EOS Install GNU's GCC: diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb index 1e636f15ff..9f51d5ec92 100644 --- a/Library/Homebrew/extend/os/mac/diagnostic.rb +++ b/Library/Homebrew/extend/os/mac/diagnostic.rb @@ -107,12 +107,7 @@ module Homebrew return if Homebrew::EnvConfig.developer? who = +"We" - # TODO: remove when Big Sur is supported. - what = if MacOS.version == :big_sur - return if ENV["HOMEBREW_GITHUB_ACTIONS_BIG_SUR_TESTING"] - - "released but not yet supported version" - elsif OS::Mac.prerelease? + what = if OS::Mac.prerelease? "pre-release version" elsif OS::Mac.outdated_release? who << " (and Apple)" diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb index 633768d805..d882025a2b 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb @@ -2,6 +2,9 @@ # frozen_string_literal: true module SharedEnvExtension + extend T::Sig + + sig { returns(T::Boolean) } def no_weak_imports_support? return false unless compiler == :clang diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index 999c916b70..4e541a2be9 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -2,6 +2,8 @@ # frozen_string_literal: true module Superenv + extend T::Sig + class << self undef bin @@ -44,6 +46,7 @@ module Superenv end # @private + sig { returns(T::Boolean) } def libxml2_include_needed? return false if deps.any? { |d| d.name == "libxml2" } return false if Pathname("#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml").directory? diff --git a/Library/Homebrew/extend/os/mac/formula.rb b/Library/Homebrew/extend/os/mac/formula.rb index 3834f8c040..ed9f64a4b4 100644 --- a/Library/Homebrew/extend/os/mac/formula.rb +++ b/Library/Homebrew/extend/os/mac/formula.rb @@ -4,8 +4,8 @@ class Formula undef on_macos - def on_macos(&_block) - raise "No block content defined for on_macos block" unless block_given? + def on_macos(&block) + raise "No block content defined for on_macos block" unless block yield end @@ -13,8 +13,8 @@ class Formula class << self undef on_macos - def on_macos(&_block) - raise "No block content defined for on_macos block" unless block_given? + def on_macos(&block) + raise "No block content defined for on_macos block" unless block yield end diff --git a/Library/Homebrew/extend/os/mac/hardware/cpu.rb b/Library/Homebrew/extend/os/mac/hardware/cpu.rb index 746786f98d..7b10da535a 100644 --- a/Library/Homebrew/extend/os/mac/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/mac/hardware/cpu.rb @@ -116,7 +116,7 @@ module Hardware sysctl_bool("hw.optional.sse4_2") end - # Note: this is more reliable than checking uname. + # NOTE: this is more reliable than checking uname. # `sysctl` returns the right answer even when running in Rosetta 2. def physical_cpu_arm64? sysctl_bool("hw.optional.arm64") diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb index 896bc69c85..eae8373747 100644 --- a/Library/Homebrew/extend/os/mac/keg_relocate.rb +++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb @@ -77,7 +77,7 @@ class Keg # remove all RPATHs from the file. if ENV["HOMEBREW_RELOCATE_METAVARS"] && file.dynamically_linked_libraries.none? { |lib| lib.start_with?("@rpath") } - # Note: This could probably be made more efficient by reverse-sorting + # NOTE: This could probably be made more efficient by reverse-sorting # the RPATHs by offset and calling MachOFile#delete_command # with repopulate: false. file.rpaths.each { |r| file.delete_rpath(r) } diff --git a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb index 4390f50675..ebb4590511 100644 --- a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb @@ -26,6 +26,13 @@ class JavaRequirement < Requirement end def java_home_cmd + # TODO: enable for all macOS versions and Linux on next minor release + # but --version is broken on Big Sur today. + if @version && MacOS.version >= :big_sur + odisabled "depends_on :java", + '"depends_on "openjdk@11", "depends_on "openjdk@8" or "depends_on "openjdk"' + end + return unless File.executable?("/usr/libexec/java_home") args = %w[--failfast] diff --git a/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb index 3ae4716a47..30510cdb20 100644 --- a/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb @@ -4,10 +4,13 @@ require "requirement" class OsxfuseRequirement < Requirement + extend T::Sig + download "https://osxfuse.github.io/" satisfy(build_env: false) { self.class.binary_osxfuse_installed? } + sig { returns(T::Boolean) } def self.binary_osxfuse_installed? File.exist?("/usr/local/include/osxfuse/fuse.h") && !File.symlink?("/usr/local/include/osxfuse") diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index 6c22d6d201..c237a7133b 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -5,6 +5,8 @@ require "resource" require "metafiles" module DiskUsageExtension + extend T::Sig + def disk_usage return @disk_usage if @disk_usage @@ -19,6 +21,7 @@ module DiskUsageExtension @file_count end + sig { returns(String) } def abv out = +"" compute_disk_usage @@ -71,6 +74,8 @@ end # Homebrew extends Ruby's `Pathname` to make our code more readable. # @see https://ruby-doc.org/stdlib-2.6.3/libdoc/pathname/rdoc/Pathname.html Ruby's Pathname API class Pathname + extend T::Sig + include DiskUsageExtension # @private @@ -282,16 +287,19 @@ class Pathname Dir.chdir(self) { yield self } end + sig { returns(T::Array[Pathname]) } def subdirs children.select(&:directory?) end # @private + sig { returns(Pathname) } def resolved_path symlink? ? dirname.join(readlink) : self end # @private + sig { returns(T::Boolean) } def resolved_path_exists? link = readlink rescue ArgumentError @@ -398,18 +406,22 @@ class Pathname end end + sig { returns(T::Boolean) } def ds_store? basename.to_s == ".DS_Store" end + sig { returns(T::Boolean) } def binary_executable? false end + sig { returns(T::Boolean) } def mach_o_bundle? false end + sig { returns(T::Boolean) } def dylib? false end @@ -420,10 +432,13 @@ require "extend/os/pathname" # @private module ObserverPathnameExtension class << self + extend T::Sig + include Context attr_accessor :n, :d + sig { void } def reset_counts! @n = @d = 0 @put_verbose_trimmed_warning = false diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 7b5e0fde35..eaed557009 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -52,6 +52,8 @@ require "utils/spdx" # end # end class Formula + extend T::Sig + include FileUtils include Utils::Inreplace include Utils::Shebang @@ -280,12 +282,13 @@ class Formula # and is specified to this instance. def installed_alias_path path = build.source["path"] if build.is_a?(Tab) - return unless path&.match?(%r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}) + return unless path&.match?(%r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}o) return unless File.symlink?(path) path end + sig { returns(T.nilable(String)) } def installed_alias_name File.basename(installed_alias_path) if installed_alias_path end @@ -354,6 +357,7 @@ class Formula # The Bottle object for the currently active {SoftwareSpec}. # @private + sig { returns(T.nilable(Bottle)) } def bottle Bottle.new(self, bottle_specification) if bottled? end @@ -407,6 +411,7 @@ class Formula end # The {PkgVersion} for this formula with {version} and {#revision} information. + sig { returns(PkgVersion) } def pkg_version PkgVersion.new(version, revision) end @@ -600,8 +605,9 @@ class Formula # The parent of the prefix; the named directory in the cellar containing all # installed versions of this software. # @private + sig { returns(Pathname) } def rack - Pathname.new("#{HOMEBREW_CELLAR}/#{name}") + HOMEBREW_CELLAR/name end # All currently installed prefix directories. @@ -888,6 +894,7 @@ class Formula end # The prefix, if any, to use in filenames for logging current activity. + sig { returns(String) } def active_log_prefix if active_log_type "#{active_log_type}." @@ -936,6 +943,7 @@ class Formula end # The generated launchd {.plist} service name. + sig { returns(String) } def plist_name "homebrew.mxcl.#{name}" end @@ -958,8 +966,9 @@ class Formula # This is the preferred way to refer to a formula in plists or from another # formula, as the path is stable even when the software is updated. #
args << "--with-readline=#{Formula["readline"].opt_prefix}" if build.with? "readline"
+ sig { returns(Pathname) } def opt_prefix - Pathname.new("#{HOMEBREW_PREFIX}/opt/#{name}") + HOMEBREW_PREFIX/"opt"/name end def opt_bin @@ -1004,6 +1013,7 @@ class Formula # Defaults to true so overridden version does not have to check if bottles # are supported. # Replaced by {.pour_bottle?}'s `satisfy` method if it is specified. + sig { returns(T::Boolean) } def pour_bottle? true end @@ -1160,11 +1170,13 @@ class Formula # @return [String, Symbol] delegate disable_reason: :"self.class" + sig { returns(T::Boolean) } def skip_cxxstdlib_check? false end # @private + sig { returns(T::Boolean) } def require_universal_deps? false end @@ -1258,10 +1270,8 @@ class Formula break end - if current_version - [] - elsif (head_version = latest_head_version) && - !head_version_outdated?(head_version, fetch_head: fetch_head) + if current_version || + ((head_version = latest_head_version) && !head_version_outdated?(head_version, fetch_head: fetch_head)) [] else all_kegs += old_installed_formulae.flat_map(&:installed_kegs) @@ -1365,6 +1375,7 @@ class Formula end # @private + sig { returns(String) } def inspect "#" end @@ -1373,16 +1384,16 @@ class Formula #
on_macos do
   # # Do something Mac-specific
   # end
- def on_macos(&_block) - raise "No block content defined for on_macos block" unless block_given? + def on_macos(&block) + raise "No block content defined for on_macos block" unless block end # Block only executed on Linux. No-op on macOS. #
on_linux do
   # # Do something Linux-specific
   # end
- def on_linux(&_block) - raise "No block content defined for on_linux block" unless block_given? + def on_linux(&block) + raise "No block content defined for on_linux block" unless block end # Standard parameters for cargo builds. @@ -1396,6 +1407,7 @@ class Formula # 3rd party installs. # Note that there isn't a std_autotools variant because autotools is a lot # less consistent and the standard parameters are more memorable. + sig { returns(T::Array[String]) } def std_cmake_args args = %W[ -DCMAKE_C_FLAGS_RELEASE=-DNDEBUG @@ -1423,6 +1435,7 @@ class Formula end # Standard parameters for cabal-v2 builds. + sig { returns(T::Array[String]) } def std_cabal_v2_args # cabal-install's dependency-resolution backtracking strategy can # easily need more than the default 2,000 maximum number of @@ -1434,6 +1447,7 @@ class Formula end # Standard parameters for meson builds. + sig { returns(T::Array[String]) } def std_meson_args ["--prefix=#{prefix}", "--libdir=#{lib}", "--buildtype=release", "--wrap-mode=nofallback"] end @@ -1869,6 +1883,7 @@ class Formula end # @private + sig { returns(T::Boolean) } def test_defined? false end @@ -2103,7 +2118,7 @@ class Formula # a block. def mkdir(name, &block) result = FileUtils.mkdir_p(name) - return result unless block_given? + return result unless block FileUtils.chdir(name, &block) end @@ -2443,7 +2458,7 @@ class Formula # end def stable(&block) @stable ||= SoftwareSpec.new(flags: build_flags) - return @stable unless block_given? + return @stable unless block @stable.instance_eval(&block) end @@ -2467,7 +2482,7 @@ class Formula #
head "https://hg.is.awesome.but.git.has.won.example.com/", using: :hg
def head(val = nil, specs = {}, &block) @head ||= HeadSoftwareSpec.new(flags: build_flags) - if block_given? + if block @head.instance_eval(&block) elsif val @head.url(val, specs) @@ -2538,16 +2553,16 @@ class Formula #
on_macos do
     #   depends_on "mac_only_dep"
     # end
- def on_macos(&_block) - raise "No block content defined for on_macos block" unless block_given? + def on_macos(&block) + raise "No block content defined for on_macos block" unless block end # Block only executed on Linux. No-op on macOS. #
on_linux do
     #   depends_on "linux_only_dep"
     # end
- def on_linux(&_block) - raise "No block content defined for on_linux block" unless block_given? + def on_linux(&block) + raise "No block content defined for on_linux block" unless block end # @!attribute [w] option @@ -2742,7 +2757,7 @@ class Formula # end def livecheck(&block) @livecheck ||= Livecheck.new(self) - return @livecheck unless block_given? + return @livecheck unless block @livecheckable = true @livecheck.instance_eval(&block) diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb new file mode 100644 index 0000000000..8c193c4603 --- /dev/null +++ b/Library/Homebrew/formula_auditor.rb @@ -0,0 +1,839 @@ +# typed: false +# frozen_string_literal: true + +require "formula_text_auditor" +require "resource_auditor" + +module Homebrew + # Auditor for checking common violations in {Formula}e. + # + # @api private + class FormulaAuditor + include FormulaCellarChecks + + attr_reader :formula, :text, :problems, :new_formula_problems + + def initialize(formula, options = {}) + @formula = formula + @versioned_formula = formula.versioned_formula? + @new_formula_inclusive = options[:new_formula] + @new_formula = options[:new_formula] && !@versioned_formula + @strict = options[:strict] + @online = options[:online] + @build_stable = options[:build_stable] + @git = options[:git] + @display_cop_names = options[:display_cop_names] + @only = options[:only] + @except = options[:except] + # Accept precomputed style offense results, for efficiency + @style_offenses = options[:style_offenses] + # Allow the formula tap to be set as homebrew/core, for testing purposes + @core_tap = formula.tap&.core_tap? || options[:core_tap] + @problems = [] + @new_formula_problems = [] + @text = FormulaTextAuditor.new(formula.path) + @specs = %w[stable head].map { |s| formula.send(s) }.compact + @spdx_license_data = options[:spdx_license_data] + @spdx_exception_data = options[:spdx_exception_data] + @tap_audit_exceptions = options[:tap_audit_exceptions] + end + + def audit_style + return unless @style_offenses + + @style_offenses.each do |offense| + correction_status = "#{Tty.green}[Corrected]#{Tty.reset} " if offense.corrected? + + cop_name = "#{offense.cop_name}: " if @display_cop_names + message = "#{cop_name}#{correction_status}#{offense.message}" + + problem message, location: offense.location + end + end + + def audit_file + if formula.core_formula? && @versioned_formula + unversioned_formula = begin + # build this ourselves as we want e.g. homebrew/core to be present + full_name = if formula.tap + "#{formula.tap}/#{formula.name}" + else + formula.name + end + Formulary.factory(full_name.gsub(/@.*$/, "")).path + rescue FormulaUnavailableError, TapFormulaAmbiguityError, + TapFormulaWithOldnameAmbiguityError + Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb") + end + unless unversioned_formula.exist? + unversioned_name = unversioned_formula.basename(".rb") + problem "#{formula} is versioned but no #{unversioned_name} formula exists" + end + elsif @build_stable && + formula.stable? && + !@versioned_formula && + (versioned_formulae = formula.versioned_formulae - [formula]) && + versioned_formulae.present? + versioned_aliases = formula.aliases.grep(/.@\d/) + _, last_alias_version = versioned_formulae.map(&:name).last.split("@") + alias_name_major = "#{formula.name}@#{formula.version.major}" + alias_name_major_minor = "#{alias_name_major}.#{formula.version.minor}" + alias_name = if last_alias_version.split(".").length == 1 + alias_name_major + else + alias_name_major_minor + end + valid_alias_names = [alias_name_major, alias_name_major_minor] + + unless @core_tap + versioned_aliases.map! { |a| "#{formula.tap}/#{a}" } + valid_alias_names.map! { |a| "#{formula.tap}/#{a}" } + end + + # Fix naming based on what people expect. + if alias_name_major_minor == "adoptopenjdk@1.8" + valid_alias_names << "adoptopenjdk@8" + valid_alias_names.delete "adoptopenjdk@1" + end + + valid_versioned_aliases = versioned_aliases & valid_alias_names + invalid_versioned_aliases = versioned_aliases - valid_alias_names + + if valid_versioned_aliases.empty? + if formula.tap + problem <<~EOS + Formula has other versions so create a versioned alias: + cd #{formula.tap.alias_dir} + ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name} + EOS + else + problem "Formula has other versions so create an alias named #{alias_name}." + end + end + + if invalid_versioned_aliases.present? + problem <<~EOS + Formula has invalid versioned aliases: + #{invalid_versioned_aliases.join("\n ")} + EOS + end + end + end + + def self.aliases + # core aliases + tap alias names + tap alias full name + @aliases ||= Formula.aliases + Formula.tap_aliases + end + + def audit_formula_name + return unless @strict + return unless @core_tap + + name = formula.name + + problem "'#{name}' is not allowed in homebrew/core." if MissingFormula.disallowed_reason(name) + + if Formula.aliases.include? name + problem "Formula name conflicts with existing aliases in homebrew/core." + return + end + + if oldname = CoreTap.instance.formula_renames[name] + problem "'#{name}' is reserved as the old name of #{oldname} in homebrew/core." + return + end + + return if formula.core_formula? + return unless Formula.core_names.include?(name) + + problem "Formula name conflicts with existing core formula." + end + + PROVIDED_BY_MACOS_DEPENDS_ON_ALLOWLIST = %w[ + apr + apr-util + libressl + openblas + openssl@1.1 + ].freeze + + PERMITTED_LICENSE_MISMATCHES = { + "AGPL-3.0" => ["AGPL-3.0-only", "AGPL-3.0-or-later"], + "GPL-2.0" => ["GPL-2.0-only", "GPL-2.0-or-later"], + "GPL-3.0" => ["GPL-3.0-only", "GPL-3.0-or-later"], + "LGPL-2.1" => ["LGPL-2.1-only", "LGPL-2.1-or-later"], + "LGPL-3.0" => ["LGPL-3.0-only", "LGPL-3.0-or-later"], + }.freeze + + PERMITTED_FORMULA_LICENSE_MISMATCHES = { + "cmockery" => "0.1.2", + "scw@1" => "1.20", + }.freeze + + def audit_license + if formula.license.present? + licenses, exceptions = SPDX.parse_license_expression formula.license + + non_standard_licenses = licenses.reject { |license| SPDX.valid_license? license } + if non_standard_licenses.present? + problem <<~EOS + Formula #{formula.name} contains non-standard SPDX licenses: #{non_standard_licenses}. + For a list of valid licenses check: #{Formatter.url("https://spdx.org/licenses/")} + EOS + end + + if @strict + deprecated_licenses = licenses.select do |license| + SPDX.deprecated_license? license + end + if deprecated_licenses.present? + problem <<~EOS + Formula #{formula.name} contains deprecated SPDX licenses: #{deprecated_licenses}. + You may need to add `-only` or `-or-later` for GNU licenses (e.g. `GPL`, `LGPL`, `AGPL`, `GFDL`). + For a list of valid licenses check: #{Formatter.url("https://spdx.org/licenses/")} + EOS + end + end + + invalid_exceptions = exceptions.reject { |exception| SPDX.valid_license_exception? exception } + if invalid_exceptions.present? + problem <<~EOS + Formula #{formula.name} contains invalid or deprecated SPDX license exceptions: #{invalid_exceptions}. + For a list of valid license exceptions check: + #{Formatter.url("https://spdx.org/licenses/exceptions-index.html")} + EOS + end + + return unless @online + + user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) + return if user.blank? + + github_license = GitHub.get_repo_license(user, repo) + return unless github_license + return if (licenses + ["NOASSERTION"]).include?(github_license) + return if PERMITTED_LICENSE_MISMATCHES[github_license]&.any? { |license| licenses.include? license } + return if PERMITTED_FORMULA_LICENSE_MISMATCHES[formula.name] == formula.version + + problem "Formula license #{licenses} does not match GitHub license #{Array(github_license)}." + + elsif @new_formula && @core_tap + problem "Formulae in homebrew/core must specify a license." + end + end + + # TODO: try to remove these, it's not a good user experience + VERSIONED_DEPENDENCIES_CONFLICTS_ALLOWLIST = %w[ + agda + anjuta + fdroidserver + gradio + predictionio + sqoop + visp + ].freeze + + def audit_deps + @specs.each do |spec| + # Check for things we don't like to depend on. + # We allow non-Homebrew installs whenever possible. + spec.deps.each do |dep| + begin + dep_f = dep.to_formula + rescue TapFormulaUnavailableError + # Don't complain about missing cross-tap dependencies + next + rescue FormulaUnavailableError + problem "Can't find dependency #{dep.name.inspect}." + next + rescue TapFormulaAmbiguityError + problem "Ambiguous dependency #{dep.name.inspect}." + next + rescue TapFormulaWithOldnameAmbiguityError + problem "Ambiguous oldname dependency #{dep.name.inspect}." + next + end + + if dep_f.oldname && dep.name.split("/").last == dep_f.oldname + problem "Dependency '#{dep.name}' was renamed; use new name '#{dep_f.name}'." + end + + if self.class.aliases.include?(dep.name) && + dep_f.core_formula? && !dep_f.versioned_formula? + problem "Dependency '#{dep.name}' from homebrew/core is an alias; " \ + "use the canonical name '#{dep.to_formula.full_name}'." + end + + if @core_tap && + @new_formula && + dep_f.keg_only? && + dep_f.keg_only_reason.provided_by_macos? && + dep_f.keg_only_reason.applicable? && + !PROVIDED_BY_MACOS_DEPENDS_ON_ALLOWLIST.include?(dep.name) + new_formula_problem( + "Dependency '#{dep.name}' is provided by macOS; " \ + "please replace 'depends_on' with 'uses_from_macos'.", + ) + end + + dep.options.each do |opt| + next if @core_tap + next if dep_f.option_defined?(opt) + next if dep_f.requirements.find do |r| + if r.recommended? + opt.name == "with-#{r.name}" + elsif r.optional? + opt.name == "without-#{r.name}" + end + end + + problem "Dependency #{dep} does not define option #{opt.name.inspect}" + end + + problem "Don't use git as a dependency (it's always available)" if @new_formula && dep.name == "git" + + problem "Dependency '#{dep.name}' is marked as :run. Remove :run; it is a no-op." if dep.tags.include?(:run) + + next unless @core_tap + + if dep.tags.include?(:recommended) || dep.tags.include?(:optional) + problem "Formulae in homebrew/core should not have optional or recommended dependencies" + end + end + + next unless @core_tap + + if spec.requirements.map(&:recommended?).any? || spec.requirements.map(&:optional?).any? + problem "Formulae in homebrew/core should not have optional or recommended requirements" + end + end + + return unless @core_tap + return if VERSIONED_DEPENDENCIES_CONFLICTS_ALLOWLIST.include?(formula.name) + + # The number of conflicts on Linux is absurd. + # TODO: remove this and check these there too. + return if OS.linux? + + recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false) + version_hash = {} + version_conflicts = Set.new + recursive_runtime_formulae.each do |f| + name = f.name + unversioned_name, = name.split("@") + version_hash[unversioned_name] ||= Set.new + version_hash[unversioned_name] << name + next if version_hash[unversioned_name].length < 2 + + version_conflicts += version_hash[unversioned_name] + end + + return if version_conflicts.empty? + + problem <<~EOS + #{formula.full_name} contains conflicting version recursive dependencies: + #{version_conflicts.to_a.join ", "} + View these with `brew deps --tree #{formula.full_name}`. + EOS + end + + def audit_conflicts + formula.conflicts.each do |c| + Formulary.factory(c.name) + rescue TapFormulaUnavailableError + # Don't complain about missing cross-tap conflicts. + next + rescue FormulaUnavailableError + problem "Can't find conflicting formula #{c.name.inspect}." + rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError + problem "Ambiguous conflicting formula #{c.name.inspect}." + end + end + + def audit_postgresql + return unless formula.name == "postgresql" + return unless @core_tap + + major_version = formula.version.major.to_i + previous_major_version = major_version - 1 + previous_formula_name = "postgresql@#{previous_major_version}" + begin + Formula[previous_formula_name] + rescue FormulaUnavailableError + problem "Versioned #{previous_formula_name} in homebrew/core must be created for " \ + "`brew-postgresql-upgrade-database` and `pg_upgrade` to work." + end + end + + # openssl@1.1 only needed for Linux + VERSIONED_KEG_ONLY_ALLOWLIST = %w[ + autoconf@2.13 + bash-completion@2 + clang-format@8 + gnupg@1.4 + libsigc++@2 + lua@5.1 + numpy@1.16 + openssl@1.1 + python@3.8 + python@3.9 + ].freeze + + def audit_versioned_keg_only + return unless @versioned_formula + return unless @core_tap + + if formula.keg_only? + return if formula.keg_only_reason.versioned_formula? + if formula.name.start_with?("openssl", "libressl") && + formula.keg_only_reason.by_macos? + return + end + end + + return if VERSIONED_KEG_ONLY_ALLOWLIST.include?(formula.name) + return if formula.name.start_with?("adoptopenjdk@") + return if formula.name.start_with?("gcc@") + + problem "Versioned formulae in homebrew/core should use `keg_only :versioned_formula`" + end + + CERT_ERROR_ALLOWLIST = { + "hashcat" => "https://hashcat.net/hashcat/", + "jinx" => "https://www.jinx-lang.org/", + "lmod" => "https://www.tacc.utexas.edu/research-development/tacc-projects/lmod", + "micropython" => "https://www.micropython.org/", + "monero" => "https://www.getmonero.org/", + }.freeze + + def audit_homepage + homepage = formula.homepage + + return if homepage.nil? || homepage.empty? + + return unless @online + + return if CERT_ERROR_ALLOWLIST[formula.name] == homepage + + return unless DevelopmentTools.curl_handles_most_https_certificates? + + if http_content_problem = curl_check_http_content(homepage, + user_agents: [:browser, :default], + check_content: true, + strict: @strict) + problem http_content_problem + end + end + + def audit_bottle_spec + # special case: new versioned formulae should be audited + return unless @new_formula_inclusive + return unless @core_tap + + return if formula.bottle_disabled? + + return unless formula.bottle_defined? + + new_formula_problem "New formulae in homebrew/core should not have a `bottle do` block" + end + + def audit_bottle_disabled + return unless formula.bottle_disabled? + return if formula.bottle_unneeded? + + problem "Unrecognized bottle modifier" unless formula.bottle_disable_reason.valid? + + return unless @core_tap + + problem "Formulae in homebrew/core should not use `bottle :disabled`" + end + + def audit_github_repository_archived + return if formula.deprecated? + + user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @online + return if user.blank? + + metadata = SharedAudits.github_repo_data(user, repo) + return if metadata.nil? + + problem "GitHub repo is archived" if metadata["archived"] + end + + def audit_gitlab_repository_archived + return if formula.deprecated? + + user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if @online + return if user.blank? + + metadata = SharedAudits.gitlab_repo_data(user, repo) + return if metadata.nil? + + problem "GitLab repo is archived" if metadata["archived"] + end + + def audit_github_repository + user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula + + return if user.blank? + + warning = SharedAudits.github(user, repo) + return if warning.nil? + + new_formula_problem warning + end + + def audit_gitlab_repository + user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if @new_formula + return if user.blank? + + warning = SharedAudits.gitlab(user, repo) + return if warning.nil? + + new_formula_problem warning + end + + def audit_bitbucket_repository + user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*}) if @new_formula + return if user.blank? + + warning = SharedAudits.bitbucket(user, repo) + return if warning.nil? + + new_formula_problem warning + end + + def get_repo_data(regex) + return unless @core_tap + return unless @online + + _, user, repo = *regex.match(formula.stable.url) if formula.stable + _, user, repo = *regex.match(formula.homepage) unless user + _, user, repo = *regex.match(formula.head.url) if !user && formula.head + return if !user || !repo + + repo.delete_suffix!(".git") + + [user, repo] + end + + UNSTABLE_ALLOWLIST = { + "aalib" => "1.4rc", + "automysqlbackup" => "3.0-rc", + "aview" => "1.3.0rc", + "elm-format" => "0.6.0-alpha", + "ftgl" => "2.1.3-rc", + "hidapi" => "0.8.0-rc", + "libcaca" => "0.99b", + "premake" => "4.4-beta", + "pwnat" => "0.3-beta", + "recode" => "3.7-beta", + "speexdsp" => "1.2rc", + "sqoop" => "1.4.", + "tcptraceroute" => "1.5beta", + "tiny-fugue" => "5.0b", + "vbindiff" => "3.0_beta", + }.freeze + + # Used for formulae that are unstable but need CI run without being in homebrew/core + UNSTABLE_DEVEL_ALLOWLIST = { + }.freeze + + GNOME_DEVEL_ALLOWLIST = { + "libart" => "2.3", + "gtk-mac-integration" => "2.1", + "gtk-doc" => "1.31", + "gcab" => "1.3", + "libepoxy" => "1.5", + }.freeze + + def audit_specs + problem "Head-only (no stable download)" if head_only?(formula) + + %w[Stable HEAD].each do |name| + spec_name = name.downcase.to_sym + next unless spec = formula.send(spec_name) + + ra = ResourceAuditor.new(spec, spec_name, online: @online, strict: @strict).audit + ra.problems.each do |message| + problem "#{name}: #{message}" + end + + spec.resources.each_value do |resource| + problem "Resource name should be different from the formula name" if resource.name == formula.name + + ra = ResourceAuditor.new(resource, spec_name, online: @online, strict: @strict).audit + ra.problems.each do |message| + problem "#{name} resource #{resource.name.inspect}: #{message}" + end + end + + next if spec.patches.empty? + next unless @new_formula + + new_formula_problem( + "Formulae should not require patches to build. " \ + "Patches should be submitted and accepted upstream first.", + ) + end + + if stable = formula.stable + version = stable.version + problem "Stable: version (#{version}) is set to a string without a digit" if version.to_s !~ /\d/ + if version.to_s.start_with?("HEAD") + problem "Stable: non-HEAD version name (#{version}) should not begin with HEAD" + end + end + + return unless @core_tap + + if formula.head && @versioned_formula && + !tap_audit_exception(:versioned_head_spec_allowlist, formula.name) + problem "Versioned formulae should not have a `HEAD` spec" + end + + stable = formula.stable + return unless stable + return unless stable.url + + stable_version_string = stable.version.to_s + stable_url_version = Version.parse(stable.url) + stable_url_minor_version = stable_url_version.minor.to_i + + formula_suffix = stable.version.patch.to_i + throttled_rate = tap_audit_exception(:throttled_formulae, formula.name) + if throttled_rate && formula_suffix.modulo(throttled_rate).nonzero? + problem "should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}" + end + + case (url = stable.url) + when /[\d._-](alpha|beta|rc\d)/ + matched = Regexp.last_match(1) + version_prefix = stable_version_string.sub(/\d+$/, "") + return if UNSTABLE_ALLOWLIST[formula.name] == version_prefix + return if UNSTABLE_DEVEL_ALLOWLIST[formula.name] == version_prefix + + problem "Stable version URLs should not contain #{matched}" + when %r{download\.gnome\.org/sources}, %r{ftp\.gnome\.org/pub/GNOME/sources}i + version_prefix = stable.version.major_minor + return if GNOME_DEVEL_ALLOWLIST[formula.name] == version_prefix + return if stable_url_version < Version.create("1.0") + return if stable_url_minor_version.even? + + problem "#{stable.version} is a development release" + when %r{isc.org/isc/bind\d*/}i + return if stable_url_minor_version.even? + + problem "#{stable.version} is a development release" + + when %r{https?://gitlab\.com/([\w-]+)/([\w-]+)} + owner = Regexp.last_match(1) + repo = Regexp.last_match(2) + + tag = SharedAudits.gitlab_tag_from_url(url) + tag ||= stable.specs[:tag] + tag ||= stable.version + + if @online + error = SharedAudits.gitlab_release(owner, repo, tag, formula: formula) + problem error if error + end + when %r{^https://github.com/([\w-]+)/([\w-]+)} + owner = Regexp.last_match(1) + repo = Regexp.last_match(2) + tag = SharedAudits.github_tag_from_url(url) + tag ||= formula.stable.specs[:tag] + + if @online + error = SharedAudits.github_release(owner, repo, tag, formula: formula) + problem error if error + end + end + end + + def audit_revision_and_version_scheme + return unless @git + return unless formula.tap # skip formula not from core or any taps + return unless formula.tap.git? # git log is required + return if formula.stable.blank? + + fv = FormulaVersions.new(formula) + + current_version = formula.stable.version + current_checksum = formula.stable.checksum + current_version_scheme = formula.version_scheme + current_revision = formula.revision + current_url = formula.stable.url + + previous_version = nil + previous_version_scheme = nil + previous_revision = nil + + newest_committed_version = nil + newest_committed_checksum = nil + newest_committed_revision = nil + newest_committed_url = nil + + fv.rev_list("origin/master") do |rev| + begin + fv.formula_at_revision(rev) do |f| + stable = f.stable + next if stable.blank? + + previous_version = stable.version + previous_checksum = stable.checksum + previous_version_scheme = f.version_scheme + previous_revision = f.revision + + newest_committed_version ||= previous_version + newest_committed_checksum ||= previous_checksum + newest_committed_revision ||= previous_revision + newest_committed_url ||= stable.url + end + rescue MacOSVersionError + break + end + + break if previous_version && current_version != previous_version + break if previous_revision && current_revision != previous_revision + end + + if current_version == newest_committed_version && + current_url == newest_committed_url && + current_checksum != newest_committed_checksum && + current_checksum.present? && newest_committed_checksum.present? + problem( + "stable sha256 changed without the url/version also changing; " \ + "please create an issue upstream to rule out malicious " \ + "circumstances and to find out why the file changed.", + ) + end + + if !newest_committed_version.nil? && + current_version < newest_committed_version && + current_version_scheme == previous_version_scheme + problem "stable version should not decrease (from #{newest_committed_version} to #{current_version})" + end + + unless previous_version_scheme.nil? + if current_version_scheme < previous_version_scheme + problem "version_scheme should not decrease (from #{previous_version_scheme} " \ + "to #{current_version_scheme})" + elsif current_version_scheme > (previous_version_scheme + 1) + problem "version_schemes should only increment by 1" + end + end + + if (previous_version != newest_committed_version || + current_version != newest_committed_version) && + !current_revision.zero? && + current_revision == newest_committed_revision && + current_revision == previous_revision + problem "'revision #{current_revision}' should be removed" + elsif current_version == previous_version && + !previous_revision.nil? && + current_revision < previous_revision + problem "revision should not decrease (from #{previous_revision} to #{current_revision})" + elsif newest_committed_revision && + current_revision > (newest_committed_revision + 1) + problem "revisions should only increment by 1" + end + end + + def audit_text + bin_names = Set.new + bin_names << formula.name + bin_names += formula.aliases + [formula.bin, formula.sbin].each do |dir| + next unless dir.exist? + + bin_names += dir.children.map(&:basename).map(&:to_s) + end + shell_commands = ["system", "shell_output", "pipe_output"] + bin_names.each do |name| + shell_commands.each do |cmd| + if text.to_s.match?(/test do.*#{cmd}[(\s]+['"]#{Regexp.escape(name)}[\s'"]/m) + problem %Q(fully scope test #{cmd} calls, e.g. #{cmd} "\#{bin}/#{name}") + end + end + end + end + + def audit_reverse_migration + # Only enforce for new formula being re-added to core + return unless @strict + return unless @core_tap + return unless formula.tap.tap_migrations.key?(formula.name) + + problem <<~EOS + #{formula.name} seems to be listed in tap_migrations.json! + Please remove #{formula.name} from present tap & tap_migrations.json + before submitting it to Homebrew/homebrew-#{formula.tap.repo}. + EOS + end + + def audit_prefix_has_contents + return unless formula.prefix.directory? + return unless Keg.new(formula.prefix).empty_installation? + + problem <<~EOS + The installation seems to be empty. Please ensure the prefix + is set correctly and expected files are installed. + The prefix configure/make argument may be case-sensitive. + EOS + end + + def quote_dep(dep) + dep.is_a?(Symbol) ? dep.inspect : "'#{dep}'" + end + + def problem_if_output(output) + problem(output) if output + end + + def audit + only_audits = @only + except_audits = @except + + methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name| + name = audit_method_name.delete_prefix("audit_") + if only_audits + next unless only_audits.include?(name) + elsif except_audits + next if except_audits.include?(name) + end + send(audit_method_name) + end + end + + private + + def problem(message, location: nil) + @problems << ({ message: message, location: location }) + end + + def new_formula_problem(message, location: nil) + @new_formula_problems << ({ message: message, location: location }) + end + + def head_only?(formula) + formula.head && formula.stable.nil? + end + + def tap_audit_exception(list, formula, value = nil) + return false unless @tap_audit_exceptions.key? list + + list = @tap_audit_exceptions[list] + + case list + when Array + list.include? formula + when Hash + return false unless list.include? formula + return list[formula] if value.blank? + + list[formula] == value + end + end + end +end diff --git a/Library/Homebrew/formula_creator.rb b/Library/Homebrew/formula_creator.rb index f30b7082ff..fd9472c2db 100644 --- a/Library/Homebrew/formula_creator.rb +++ b/Library/Homebrew/formula_creator.rb @@ -9,6 +9,8 @@ module Homebrew # # @api private class FormulaCreator + extend T::Sig + attr_reader :args, :url, :sha256, :desc, :homepage attr_accessor :name, :version, :tap, :path, :mode, :license @@ -88,6 +90,7 @@ module Homebrew path.write ERB.new(template, trim_mode: ">").result(binding) end + sig { returns(String) } def template <<~ERB # Documentation: https://docs.brew.sh/Formula-Cookbook diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index aae10e1af1..ee2d2b0218 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -28,60 +28,70 @@ require "unlink" # # @api private class FormulaInstaller + extend T::Sig + include FormulaCellarChecks extend Predicable - def self.mode_attr_accessor(*names) - attr_accessor(*names) - - private(*names) - names.each do |name| - predicate = "#{name}?" - define_method(predicate) do - send(name) ? true : false - end - private(predicate) - end - end - attr_reader :formula - attr_accessor :cc, :env, :options, :build_bottle, :bottle_arch, - :build_from_source_formulae, :include_test_formulae, - :installed_as_dependency, :installed_on_request, :link_keg, :other_installers - mode_attr_accessor :show_summary_heading, :show_header - mode_attr_accessor :force_bottle, :ignore_deps, :only_deps, :interactive, :git, :force, :keep_tmp - mode_attr_accessor :verbose, :debug, :quiet + attr_accessor :options, :link_keg - def initialize(formula, - force_bottle: false, - include_test_formulae: [], - build_from_source_formulae: [], - cc: nil, - debug: false, quiet: false, verbose: false) + attr_predicate :installed_as_dependency?, :installed_on_request? + attr_predicate :show_summary_heading?, :show_header? + attr_predicate :force_bottle?, :ignore_deps?, :only_deps?, :interactive?, :git?, :force?, :keep_tmp? + attr_predicate :verbose?, :debug?, :quiet? + + # TODO: Remove when removed from `test-bot`. + attr_writer :build_bottle + + def initialize( + formula, + link_keg: false, + installed_as_dependency: false, + installed_on_request: true, + show_header: false, + build_bottle: false, + force_bottle: false, + bottle_arch: nil, + ignore_deps: false, + only_deps: false, + include_test_formulae: [], + build_from_source_formulae: [], + env: nil, + git: false, + interactive: false, + keep_tmp: false, + cc: nil, + options: Options.new, + force: false, + debug: false, + quiet: false, + verbose: false + ) @formula = formula - @env = nil - @force = false - @keep_tmp = false - @link_keg = !formula.keg_only? - @show_header = false - @ignore_deps = false - @only_deps = false + @env = env + @force = force + @keep_tmp = keep_tmp + @link_keg = !formula.keg_only? || link_keg + @show_header = show_header + @ignore_deps = ignore_deps + @only_deps = only_deps @build_from_source_formulae = build_from_source_formulae - @build_bottle = false - @bottle_arch = nil + @build_bottle = build_bottle + @bottle_arch = bottle_arch @formula.force_bottle ||= force_bottle @force_bottle = @formula.force_bottle @include_test_formulae = include_test_formulae - @interactive = false - @git = false + @interactive = interactive + @git = git @cc = cc @verbose = verbose @quiet = quiet @debug = debug - @installed_as_dependency = false - @installed_on_request = true - @options = Options.new + @installed_as_dependency = installed_as_dependency + @installed_on_request = installed_on_request + @options = options @requirement_messages = [] @poured_bottle = false @pour_failed = false @@ -92,6 +102,7 @@ class FormulaInstaller @attempted ||= Set.new end + sig { void } def self.clear_attempted @attempted = Set.new end @@ -100,6 +111,7 @@ class FormulaInstaller @installed ||= Set.new end + sig { void } def self.clear_installed @installed = Set.new end @@ -123,27 +135,31 @@ class FormulaInstaller raise BuildFlagsError.new(build_flags, bottled: all_bottled) end + sig { returns(T::Boolean) } def build_from_source? - build_from_source_formulae.include?(formula.full_name) + @build_from_source_formulae.include?(formula.full_name) end + sig { returns(T::Boolean) } def include_test? - include_test_formulae.include?(formula.full_name) + @include_test_formulae.include?(formula.full_name) end + sig { returns(T::Boolean) } def build_bottle? return false unless @build_bottle !formula.bottle_disabled? end + sig { params(install_bottle_options: { warn: T::Boolean }).returns(T::Boolean) } def pour_bottle?(install_bottle_options = { warn: false }) return false if @pour_failed return false if !formula.bottled? && !formula.local_bottle_path return true if force_bottle? return false if build_from_source? || build_bottle? || interactive? - return false if cc + return false if @cc return false unless options.empty? return false if formula.bottle_disabled? @@ -171,16 +187,18 @@ class FormulaInstaller true end + sig { params(dep: Formula, build: BuildOptions).returns(T::Boolean) } def install_bottle_for?(dep, build) return pour_bottle? if dep == formula - return false if build_from_source_formulae.include?(dep.full_name) + return false if @build_from_source_formulae.include?(dep.full_name) return false unless dep.bottle && dep.pour_bottle? return false unless build.used_options.empty? - return false unless dep.bottle.compatible_cellar? + return false unless dep.bottle&.compatible_cellar? true end + sig { void } def prelude Tab.clear_cache verify_deps_exist unless ignore_deps? @@ -189,6 +207,7 @@ class FormulaInstaller check_install_sanity end + sig { void } def verify_deps_exist begin compute_dependencies @@ -293,6 +312,7 @@ class FormulaInstaller end end + sig { void } def install lock @@ -344,7 +364,7 @@ class FormulaInstaller return if only_deps? - if build_bottle? && (arch = bottle_arch) && !Hardware::CPU.optimization_flags.include?(arch.to_sym) + if build_bottle? && (arch = @bottle_arch) && !Hardware::CPU.optimization_flags.include?(arch.to_sym) raise CannotInstallFormulaError, "Unrecognized architecture for --bottle-arch: #{arch}" end @@ -361,7 +381,7 @@ class FormulaInstaller action = "#{formula.full_name} #{options}".strip Utils::Analytics.report_event("install", action) - Utils::Analytics.report_event("install_on_request", action) if installed_on_request + Utils::Analytics.report_event("install_on_request", action) if installed_on_request? end self.class.attempted << formula @@ -419,8 +439,8 @@ class FormulaInstaller keg = Keg.new(formula.prefix) tab = Tab.for_keg(keg) - tab.installed_as_dependency = installed_as_dependency - tab.installed_on_request = installed_on_request + tab.installed_as_dependency = installed_as_dependency? + tab.installed_on_request = installed_on_request? tab.write end @@ -532,13 +552,10 @@ class FormulaInstaller keep_build_test ||= req.test? && include_test? && dependent == f keep_build_test ||= req.build? && !install_bottle_for_dependent && !dependent.latest_version_installed? - if req.prune_from_option?(build) - Requirement.prune - elsif req.satisfied?(env: env, cc: cc, build_bottle: @build_bottle, bottle_arch: bottle_arch) - Requirement.prune - elsif (req.build? || req.test?) && !keep_build_test - Requirement.prune - elsif (dep = formula_deps_map[dependent.name]) && dep.build? + if req.prune_from_option?(build) || + req.satisfied?(env: @env, cc: @cc, build_bottle: @build_bottle, bottle_arch: @bottle_arch) || + ((req.build? || req.test?) && !keep_build_test) || + formula_deps_map[dependent.name]&.build? Requirement.prune else unsatisfied_reqs[dependent] << req @@ -564,12 +581,10 @@ class FormulaInstaller ) keep_build_test = false - keep_build_test ||= dep.test? && include_test? && include_test_formulae.include?(dependent.full_name) + keep_build_test ||= dep.test? && include_test? && @include_test_formulae.include?(dependent.full_name) keep_build_test ||= dep.build? && !install_bottle_for?(dependent, build) && !dependent.latest_version_installed? - if dep.prune_from_option?(build) - Dependency.prune - elsif (dep.build? || dep.test?) && !keep_build_test + if dep.prune_from_option?(build) || ((dep.build? || dep.test?) && !keep_build_test) Dependency.prune elsif dep.satisfied?(inherited_options[dep.name]) Dependency.skip @@ -615,6 +630,7 @@ class FormulaInstaller options end + sig { params(dep: Dependency).returns(Options) } def inherited_options_for(dep) inherited_options = Options.new u = Option.new("universal") @@ -624,6 +640,7 @@ class FormulaInstaller inherited_options end + sig { params(deps: T::Array[[Formula, Options]]).void } def install_dependencies(deps) if deps.empty? && only_deps? puts "All dependencies for #{formula.full_name} are satisfied." @@ -637,22 +654,28 @@ class FormulaInstaller @show_header = true unless deps.empty? end + sig { params(dep: Formula).void } def fetch_dependency(dep) df = dep.to_formula - fi = FormulaInstaller.new(df, force_bottle: false, - include_test_formulae: include_test_formulae, - build_from_source_formulae: build_from_source_formulae, - debug: debug?, quiet: quiet?, verbose: verbose?) - - fi.force = force? - fi.keep_tmp = keep_tmp? - # When fetching we don't need to recurse the dependency tree as it's already - # been done for us in `compute_dependencies` and there's no requirement to - # fetch in a particular order. - fi.ignore_deps = true + fi = FormulaInstaller.new( + df, + force_bottle: false, + # When fetching we don't need to recurse the dependency tree as it's already + # been done for us in `compute_dependencies` and there's no requirement to + # fetch in a particular order. + ignore_deps: true, + include_test_formulae: @include_test_formulae, + build_from_source_formulae: @build_from_source_formulae, + keep_tmp: keep_tmp?, + force: force?, + debug: debug?, + quiet: quiet?, + verbose: verbose?, + ) fi.fetch end + sig { params(dep: Formula, inherited_options: Options).void } def install_dependency(dep, inherited_options) df = dep.to_formula tab = Tab.for_formula(df) @@ -678,20 +701,29 @@ class FormulaInstaller EOS end - fi = FormulaInstaller.new(df, force_bottle: false, - include_test_formulae: include_test_formulae, - build_from_source_formulae: build_from_source_formulae, - debug: debug?, quiet: quiet?, verbose: verbose?) + options = Options.new + options |= tab.used_options + options |= Tab.remap_deprecated_options(df.deprecated_options, dep.options) + options |= inherited_options + options &= df.options - fi.options |= tab.used_options - fi.options |= Tab.remap_deprecated_options(df.deprecated_options, dep.options) - fi.options |= inherited_options - fi.options &= df.options - fi.force = force? - fi.keep_tmp = keep_tmp? - fi.link_keg ||= keg_was_linked if keg_had_linked_keg - fi.installed_as_dependency = true - fi.installed_on_request = df.any_version_installed? && tab.installed_on_request + fi = FormulaInstaller.new( + df, + **{ + options: options, + link_keg: keg_had_linked_keg ? keg_was_linked : nil, + installed_as_dependency: true, + installed_on_request: df.any_version_installed? && tab.installed_on_request, + force_bottle: false, + include_test_formulae: @include_test_formulae, + build_from_source_formulae: @build_from_source_formulae, + keep_tmp: keep_tmp?, + force: force?, + debug: debug?, + quiet: quiet?, + verbose: verbose?, + }, + ) fi.prelude oh1 "Installing #{formula.full_name} dependency: #{Formatter.identifier(dep.name)}" fi.install @@ -710,6 +742,7 @@ class FormulaInstaller ignore_interrupts { tmp_keg.rmtree if tmp_keg&.directory? } end + sig { void } def caveats return if only_deps? @@ -724,6 +757,7 @@ class FormulaInstaller Homebrew.messages.record_caveats(formula, caveats) end + sig { void } def finish return if only_deps? @@ -776,6 +810,7 @@ class FormulaInstaller unlock end + sig { returns(String) } def summary s = +"" s << "#{Homebrew::EnvConfig.install_badge} " unless Homebrew::EnvConfig.no_emoji? @@ -788,24 +823,25 @@ class FormulaInstaller @build_time ||= Time.now - @start_time if @start_time && !interactive? end + sig { returns(T::Array[String]) } def sanitized_argv_options args = [] args << "--ignore-dependencies" if ignore_deps? if build_bottle? args << "--build-bottle" - args << "--bottle-arch=#{bottle_arch}" if bottle_arch + args << "--bottle-arch=#{@bottle_arch}" if @bottle_arch end args << "--git" if git? args << "--interactive" if interactive? args << "--verbose" if verbose? args << "--debug" if debug? - args << "--cc=#{cc}" if cc + args << "--cc=#{@cc}" if @cc args << "--keep-tmp" if keep_tmp? - if env.present? - args << "--env=#{env}" + if @env.present? + args << "--env=#{@env}" elsif formula.env.std? || formula.deps.select(&:build?).any? { |d| d.name == "scons" } args << "--env=std" end @@ -815,10 +851,12 @@ class FormulaInstaller args end + sig { returns(T::Array[String]) } def build_argv sanitized_argv_options + options.as_flags end + sig { void } def build FileUtils.rm_rf(formula.logs) @@ -872,6 +910,7 @@ class FormulaInstaller raise e end + sig { params(keg: Keg).void } def link(keg) Formula.clear_cache @@ -962,6 +1001,7 @@ class FormulaInstaller @show_summary_heading = true end + sig { void } def install_plist return unless formula.plist @@ -975,6 +1015,7 @@ class FormulaInstaller Homebrew.failed = true end + sig { params(keg: Keg).void } def fix_dynamic_linkage(keg) keg.fix_dynamic_linkage rescue Exception => e # rubocop:disable Lint/RescueException @@ -986,6 +1027,7 @@ class FormulaInstaller @show_summary_heading = true end + sig { void } def clean ohai "Cleaning" if verbose? Cleaner.new(formula).clean @@ -997,6 +1039,7 @@ class FormulaInstaller @show_summary_heading = true end + sig { void } def post_install args = %W[ nice #{RUBY_PATH} @@ -1033,6 +1076,7 @@ class FormulaInstaller @show_summary_heading = true end + sig { void } def fetch_dependencies return if ignore_deps? @@ -1042,6 +1086,7 @@ class FormulaInstaller deps.each { |dep, _options| fetch_dependency(dep) } end + sig { void } def fetch fetch_dependencies @@ -1079,6 +1124,7 @@ class FormulaInstaller end end + sig { void } def pour HOMEBREW_CELLAR.cd do downloader.stage @@ -1103,12 +1149,13 @@ class FormulaInstaller tab.time = Time.now.to_i tab.head = HOMEBREW_REPOSITORY.git_head tab.source["path"] = formula.specified_path.to_s - tab.installed_as_dependency = installed_as_dependency - tab.installed_on_request = installed_on_request + tab.installed_as_dependency = installed_as_dependency? + tab.installed_on_request = installed_on_request? tab.aliases = formula.aliases tab.write end + sig { params(output: T.nilable(String)).void } def problem_if_output(output) return unless output @@ -1132,6 +1179,7 @@ class FormulaInstaller attr_predicate :hold_locks? + sig { void } def lock return unless self.class.locked.empty? @@ -1146,6 +1194,7 @@ class FormulaInstaller @hold_locks = true end + sig { void } def unlock return unless hold_locks? @@ -1161,6 +1210,7 @@ class FormulaInstaller $stderr.puts @requirement_messages end + sig { void } def forbidden_license_check forbidden_licenses = Homebrew::EnvConfig.forbidden_licenses.to_s.dup SPDX::ALLOWED_LICENSE_SYMBOLS.each do |s| diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb index 287ffd0f0c..fce3bed2bc 100644 --- a/Library/Homebrew/formula_support.rb +++ b/Library/Homebrew/formula_support.rb @@ -7,6 +7,8 @@ FormulaConflict = Struct.new(:name, :reason) # Used to annotate formulae that duplicate macOS-provided software # or cause conflicts when linked in. class KegOnlyReason + extend T::Sig + attr_reader :reason def initialize(reason, explanation) @@ -30,6 +32,7 @@ class KegOnlyReason provided_by_macos? || shadowed_by_macos? end + sig { returns(T::Boolean) } def applicable? # macOS reasons aren't applicable on other OSs # (see extend/os/mac/formula_support for override on macOS) diff --git a/Library/Homebrew/formula_text_auditor.rb b/Library/Homebrew/formula_text_auditor.rb new file mode 100644 index 0000000000..02c6069d35 --- /dev/null +++ b/Library/Homebrew/formula_text_auditor.rb @@ -0,0 +1,40 @@ +# typed: false +# frozen_string_literal: true + +module Homebrew + # Auditor for checking common violations in {Formula} text content. + # + # @api private + class FormulaTextAuditor + def initialize(path) + @text = path.open("rb", &:read) + @lines = @text.lines.to_a + end + + def without_patch + @text.split("\n__END__").first + end + + def trailing_newline? + /\Z\n/ =~ @text + end + + def =~(other) + other =~ @text + end + + def include?(s) + @text.include? s + end + + def line_number(regex, skip = 0) + index = @lines.drop(skip).index { |line| line =~ regex } + index ? index + 1 : nil + end + + def reverse_line_number(regex) + index = @lines.reverse.index { |line| line =~ regex } + index ? @lines.count - index : nil + end + end +end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 3be8bbd3ef..efe4ef24b4 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -10,10 +10,13 @@ require "tab" # # @api private module Formulary + extend T::Sig + extend Cachable URL_START_REGEX = %r{(https?|ftp|file)://}.freeze + sig { void } def self.enable_factory_cache! @factory_cache = true end @@ -208,8 +211,11 @@ module Formulary # Loads formulae from URLs. class FromUrlLoader < FormulaLoader + extend T::Sig + attr_reader :url + sig { params(url: T.any(URI::Generic, String)).void } def initialize(url) @url = url uri = URI(url) diff --git a/Library/Homebrew/hardware.rb b/Library/Homebrew/hardware.rb index 11c78eaf58..88625b72a3 100644 --- a/Library/Homebrew/hardware.rb +++ b/Library/Homebrew/hardware.rb @@ -13,6 +13,8 @@ module Hardware PPC_64BIT_ARCHS = [:ppc64, :ppc64le, :ppc970].freeze class << self + extend T::Sig + def optimization_flags @optimization_flags ||= { native: arch_flag("native"), @@ -29,6 +31,7 @@ module Hardware end alias generic_optimization_flags optimization_flags + sig { returns(Symbol) } def arch_32_bit if arm? :arm @@ -41,6 +44,7 @@ module Hardware end end + sig { returns(Symbol) } def arch_64_bit if arm? :arm64 @@ -70,6 +74,7 @@ module Hardware [arch].extend ArchitectureListExtension end + sig { returns(Symbol) } def type case RUBY_PLATFORM when /x86_64/, /i\d86/ then :intel @@ -79,6 +84,7 @@ module Hardware end end + sig { returns(Symbol) } def family :dunno end @@ -98,6 +104,7 @@ module Hardware end end + sig { returns(T::Boolean) } def sse4? RUBY_PLATFORM.to_s.include?("x86_64") end @@ -156,6 +163,7 @@ module Hardware "-march=#{arch}" end + sig { returns(T::Boolean) } def in_rosetta2? false end diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index d46d0dc67e..80ba0608bd 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -11,6 +11,8 @@ require "extend/cachable" # # @api private class Keg + extend T::Sig + extend Cachable # Error for when a keg is already linked. @@ -39,6 +41,9 @@ class Keg # Error for when a file already exists or belongs to another keg. class ConflictError < LinkError + extend T::Sig + + sig { returns(String) } def suggestion conflict = Keg.for(dst) rescue NotAKegError, Errno::ENOENT @@ -50,6 +55,7 @@ class Keg EOS end + sig { returns(String) } def to_s s = [] s << "Could not symlink #{src}" @@ -67,6 +73,9 @@ class Keg # Error for when a directory is not writable. class DirectoryNotWritableError < LinkError + extend T::Sig + + sig { returns(String) } def to_s <<~EOS Could not symlink #{src} @@ -226,6 +235,7 @@ class Keg alias to_path to_s + sig { returns(String) } def inspect "#<#{self.class.name}:#{path}>" end @@ -235,6 +245,7 @@ class Keg end alias eql? == + sig { returns(T::Boolean) } def empty_installation? Pathname.glob("#{path}/*") do |file| return false if file.directory? && !file.children.reject(&:ds_store?).empty? @@ -411,6 +422,7 @@ class Keg end end + sig { returns(T::Boolean) } def plist_installed? !Dir["#{path}/*.plist"].empty? end @@ -419,10 +431,12 @@ class Keg (path/"lib/python2.7/site-packages").directory? end + sig { returns(T::Boolean) } def python_pth_files_installed? !Dir["#{path}/lib/python2.7/site-packages/*.pth"].empty? end + sig { returns(T::Array[Pathname]) } def apps app_prefix = optlinked? ? opt_record : path Pathname.glob("#{app_prefix}/{,libexec/}*.app") @@ -468,45 +482,46 @@ class Keg link_dir("share", **options) do |relative_path| case relative_path.to_s - when "locale/locale.alias" then :skip_file when INFOFILE_RX then :info - when LOCALEDIR_RX then :mkpath - when %r{^icons/.*/icon-theme\.cache$} then :skip_file - # all icons subfolders should also mkpath - when %r{^icons/} then :mkpath - when /^zsh/ then :mkpath - when /^fish/ then :mkpath - # Lua, Lua51, Lua53 all need the same handling. - when %r{^lua/} then :mkpath - when %r{^guile/} then :mkpath - when *SHARE_PATHS then :mkpath - else :link + when "locale/locale.alias", + %r{^icons/.*/icon-theme\.cache$} + :skip_file + when LOCALEDIR_RX, + %r{^icons/}, # all icons subfolders should also mkpath + /^zsh/, + /^fish/, + %r{^lua/}, # Lua, Lua51, Lua53 all need the same handling. + %r{^guile/}, + *SHARE_PATHS + :mkpath + else + :link end end link_dir("lib", **options) do |relative_path| case relative_path.to_s - when "charset.alias" then :skip_file - # pkg-config database gets explicitly created - when "pkgconfig" then :mkpath - # cmake database gets explicitly created - when "cmake" then :mkpath - # lib/language folders also get explicitly created - when "dtrace" then :mkpath - when /^gdk-pixbuf/ then :mkpath - when "ghc" then :mkpath - when /^gio/ then :mkpath - when "lua" then :mkpath - when /^mecab/ then :mkpath - when /^node/ then :mkpath - when /^ocaml/ then :mkpath - when /^perl5/ then :mkpath - when "php" then :mkpath - when /^python[23]\.\d/ then :mkpath - when /^R/ then :mkpath - when /^ruby/ then :mkpath - # Everything else is symlinked to the cellar - else :link + when "charset.alias" + :skip_file + when "pkgconfig", # pkg-config database gets explicitly created + "cmake", # cmake database gets explicitly created + "dtrace", # lib/language folders also get explicitly created + /^gdk-pixbuf/, + "ghc", + /^gio/, + "lua", + /^mecab/, + /^node/, + /^ocaml/, + /^perl5/, + "php", + /^python[23]\.\d/, + /^R/, + /^ruby/ + :mkpath + else + # Everything else is symlinked to the cellar + :link end end diff --git a/Library/Homebrew/language/node.rb b/Library/Homebrew/language/node.rb index e30c9ba744..1e5e48f7b5 100644 --- a/Library/Homebrew/language/node.rb +++ b/Library/Homebrew/language/node.rb @@ -6,6 +6,9 @@ module Language # # @api public module Node + extend T::Sig + + sig { returns(String) } def self.npm_cache_config "cache=#{HOMEBREW_CACHE}/npm_cache" end @@ -73,6 +76,7 @@ module Language args end + sig { returns(T::Array[String]) } def self.local_npm_install_args setup_npm_environment # npm install args for local style module format diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb index a60343a704..165ee1da28 100644 --- a/Library/Homebrew/language/python.rb +++ b/Library/Homebrew/language/python.rb @@ -114,6 +114,8 @@ module Language # Mixin module for {Formula} adding virtualenv support features. module Virtualenv + extend T::Sig + def self.included(base) base.class_eval do resource "homebrew-virtualenv" do @@ -215,6 +217,7 @@ module Language venv end + sig { returns(T::Array[String]) } def python_names %w[python python3 pypy pypy3] + Formula.names.select { |name| name.start_with? "python@" } end @@ -267,7 +270,7 @@ module Language next unless f.symlink? next unless (rp = f.realpath.to_s).start_with? HOMEBREW_CELLAR - version = rp.match %r{^#{HOMEBREW_CELLAR}/python@(.*?)/} + version = rp.match %r{^#{HOMEBREW_CELLAR}/python@(.*?)/}o version = "@#{version.captures.first}" unless version.nil? new_target = rp.sub %r{#{HOMEBREW_CELLAR}/python#{version}/[^/]+}, Formula["python#{version}"].opt_prefix @@ -278,7 +281,7 @@ module Language Pathname.glob(@venv_root/"lib/python*/orig-prefix.txt").each do |prefix_file| prefix_path = prefix_file.read - version = prefix_path.match %r{^#{HOMEBREW_CELLAR}/python@(.*?)/} + version = prefix_path.match %r{^#{HOMEBREW_CELLAR}/python@(.*?)/}o version = "@#{version.captures.first}" unless version.nil? prefix_path.sub! %r{^#{HOMEBREW_CELLAR}/python#{version}/[^/]+}, Formula["python#{version}"].opt_prefix diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 67ab46e093..ef189d011d 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -10,6 +10,8 @@ require "fiddle" # # @api private class LinkageChecker + extend T::Sig + attr_reader :undeclared_deps, :keg, :formula, :store def initialize(keg, formula = nil, cache_db:, rebuild_cache: false) @@ -78,6 +80,7 @@ class LinkageChecker puts "Unexpected non-missing linkage detected" if unexpected_present_dylibs.present? end + sig { returns(T::Boolean) } def broken_library_linkage? issues = [@broken_deps, @unwanted_system_dylibs, @version_conflict_deps] [issues, unexpected_broken_dylibs, unexpected_present_dylibs].flatten.any?(&:present?) @@ -126,7 +129,7 @@ class LinkageChecker private def dylib_to_dep(dylib) - dylib =~ %r{#{Regexp.escape(HOMEBREW_PREFIX)}/(opt|Cellar)/([\w+-.@]+)/} + dylib =~ %r{#{Regexp.escape(HOMEBREW_PREFIX)}/(opt|Cellar)/([\w+-.@]+)/}o Regexp.last_match(2) end diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index 7e90808ea8..fae6e91804 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -233,6 +233,13 @@ module Homebrew return end + if formula.disabled? && !formula.livecheckable? + return status_hash(formula, "disabled", args: args) if args.json? + + puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : disabled" unless args.quiet? + return + end + if formula.versioned_formula? && !formula.livecheckable? return status_hash(formula, "versioned", args: args) if args.json? diff --git a/Library/Homebrew/locale.rb b/Library/Homebrew/locale.rb index 7a9ee544ca..fcfa56f80f 100644 --- a/Library/Homebrew/locale.rb +++ b/Library/Homebrew/locale.rb @@ -7,7 +7,9 @@ # # @api private class Locale - # Error when a string cannot be parsed to a {Locale}. + extend T::Sig + + # Error when a string cannot be parsed to a `Locale`. class ParserError < StandardError end @@ -34,6 +36,7 @@ class Locale raise ParserError, "'#{string}' cannot be parsed to a #{self}" end + sig { params(string: String).returns(T.nilable(T.attached_class)) } def self.try_parse(string) return if string.blank? @@ -107,6 +110,7 @@ class Locale locale_groups.find { |locales| locales.any? { |locale| include?(locale) } } end + sig { returns(String) } def to_s [@language, @region, @script].compact.join("-") end diff --git a/Library/Homebrew/manpages/brew.1.md.erb b/Library/Homebrew/manpages/brew.1.md.erb index 6d4773cd77..ba4d02d0f7 100644 --- a/Library/Homebrew/manpages/brew.1.md.erb +++ b/Library/Homebrew/manpages/brew.1.md.erb @@ -1,16 +1,20 @@ <% # To make changes to this man page: # -# - For changes to a specific command (appears in the `COMMANDS` section): -# - Edit the top comment in `Library/Homebrew/cmd/.{rb,sh}`. -# - Make sure to use the line prefix `#:` for the comments to be recognized as -# documentation. If in doubt, compare with already documented commands. +# - For changes to a command under `COMMANDS` or `DEVELOPER COMMANDS` sections): +# - Find the source file in `Library/Homebrew/[dev-]cmd/.{rb,sh}`. +# - For `.rb` files, edit the `_args` method. +# - For `.sh` files, edit the top comment, being sure to use the line prefix +# `#:` for the comments to be recognized as documentation. If in doubt, +# compare with already documented commands. +# - For global options: Edit `Library/Homebrew/cli/parser.rb`. +# - For environment variables: Edit `Library/Homebrew/env_config.rb`. # - For other changes: Edit this file. # # When done, regenerate the man page and its HTML version by running `brew man`. %> -brew(1) -- The Missing Package Manager for macOS -================================================ +brew(1) -- The Missing Package Manager for macOS (or Linux) +=========================================================== ## SYNOPSIS @@ -20,34 +24,36 @@ brew(1) -- The Missing Package Manager for macOS ## DESCRIPTION Homebrew is the easiest and most flexible way to install the UNIX tools Apple -didn't include with macOS. +didn't include with macOS. It can also install software not packaged for your +Linux distribution to your home directory without requiring `sudo`. ## ESSENTIAL COMMANDS For the full command list, see the [COMMANDS](#commands) section. -With `--verbose` or `--debug`, many commands print extra debugging information. Note that -these options should only appear after a command. +With `--verbose` or `--debug`, many commands print extra debugging information. +Note that these options should only appear after a command. -### `install` : +### `install` Install . - is usually the name of the formula to install, but it has other syntaxes which -are listed in the [SPECIFYING FORMULAE](#specifying-formulae) section. + is usually the name of the formula to install, but it has other +syntaxes which are listed in the [SPECIFYING FORMULAE](#specifying-formulae) +section. -### `uninstall` : +### `uninstall` Uninstall . -### `list`: +### `list` List all installed formulae. -### `search` (|`/``/`): +### `search` [|`/``/`] -Perform a substring search of cask tokens and formula names for . If -is flanked by slashes, it is interpreted as a regular expression. +Perform a substring search of cask tokens and formula names for . If + is flanked by slashes, it is interpreted as a regular expression. The search for is extended online to `homebrew/core` and `homebrew/cask`. If no search term is provided, all locally available formulae are listed. @@ -75,8 +81,8 @@ If no search term is provided, all locally available formulae are listed. Homebrew, like `git`(1), supports external commands. These are executable scripts that reside somewhere in the `PATH`, named `brew-` or -`brew-``.rb`, which can be invoked like `brew` . This allows you -to create your own commands without modifying Homebrew's internals. +`brew-``.rb`, which can be invoked like `brew` . This allows +you to create your own commands without modifying Homebrew's internals. Instructions for creating your own commands can be found in the docs: @@ -107,8 +113,8 @@ specified the same way as the arguments described in ## ENVIRONMENT -Note that environment variables must have a value set to be detected. For example, run -`export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just +Note that environment variables must have a value set to be detected. For +example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just `export HOMEBREW_NO_INSECURE_REDIRECT`. <%= environment_variables %> @@ -155,10 +161,10 @@ Homebrew API: See our issues on GitHub: * **Homebrew/brew**: - +
* **Homebrew/homebrew-core**: - +
* **Homebrew/homebrew-cask**: - +
diff --git a/Library/Homebrew/messages.rb b/Library/Homebrew/messages.rb index fee41654da..e212896790 100644 --- a/Library/Homebrew/messages.rb +++ b/Library/Homebrew/messages.rb @@ -4,8 +4,11 @@ # A {Messages} object collects messages that may need to be displayed together # at the end of a multi-step `brew` command run. class Messages + extend T::Sig + attr_reader :caveats, :formula_count, :install_times + sig { void } def initialize @caveats = [] @formula_count = 0 diff --git a/Library/Homebrew/migrator.rb b/Library/Homebrew/migrator.rb index 4713960d24..688a743bbf 100644 --- a/Library/Homebrew/migrator.rb +++ b/Library/Homebrew/migrator.rb @@ -9,6 +9,8 @@ require "tab" # # @api private class Migrator + extend T::Sig + include Context # Error for when a migration is necessary. @@ -155,6 +157,7 @@ class Migrator end end + sig { returns(T::Boolean) } def from_same_tap_user? formula_tap_user = formula.tap.user if formula.tap old_tap_user = nil diff --git a/Library/Homebrew/mktemp.rb b/Library/Homebrew/mktemp.rb index 5b7704d97e..e5e0277e2c 100644 --- a/Library/Homebrew/mktemp.rb +++ b/Library/Homebrew/mktemp.rb @@ -4,6 +4,8 @@ # Performs {Formula#mktemp}'s functionality, and tracks the results. # Each instance is only intended to be used once. class Mktemp + extend T::Sig + include FileUtils # Path to the tmpdir used in this run, as a {Pathname}. @@ -16,6 +18,7 @@ class Mktemp end # Instructs this {Mktemp} to retain the staged files. + sig { void } def retain! @retain = true end @@ -26,10 +29,12 @@ class Mktemp end # Instructs this Mktemp to not emit messages when retention is triggered. + sig { void } def quiet! @quiet = true end + sig { returns(String) } def to_s "[Mktemp: #{tmpdir} retain=#{@retain} quiet=#{@quiet}]" end diff --git a/Library/Homebrew/options.rb b/Library/Homebrew/options.rb index 9e4a229ed1..5102e36661 100644 --- a/Library/Homebrew/options.rb +++ b/Library/Homebrew/options.rb @@ -5,6 +5,8 @@ # # @api private class Option + extend T::Sig + attr_reader :name, :description, :flag def initialize(name, description = "") @@ -32,6 +34,7 @@ class Option name.hash end + sig { returns(String) } def inspect "#<#{self.class.name}: #{flag.inspect}>" end @@ -41,6 +44,8 @@ end # # @api private class DeprecatedOption + extend T::Sig + attr_reader :old, :current def initialize(old, current) @@ -48,10 +53,12 @@ class DeprecatedOption @current = current end + sig { returns(String) } def old_flag "--#{old}" end + sig { returns(String) } def current_flag "--#{current}" end @@ -66,6 +73,8 @@ end # # @api private class Options + extend T::Sig + include Enumerable def self.create(array) @@ -119,6 +128,7 @@ class Options alias to_ary to_a + sig { returns(String) } def inspect "#<#{self.class.name}: #{to_a.inspect}>" end diff --git a/Library/Homebrew/os/linux.rb b/Library/Homebrew/os/linux.rb index 17d2fee346..039e6ab98f 100644 --- a/Library/Homebrew/os/linux.rb +++ b/Library/Homebrew/os/linux.rb @@ -4,8 +4,11 @@ module OS # Helper module for querying system information on Linux. module Linux + extend T::Sig + module_function + sig { returns(String) } def os_version if which("lsb_release") description = Utils.popen_read("lsb_release -d") diff --git a/Library/Homebrew/os/linux/glibc.rb b/Library/Homebrew/os/linux/glibc.rb index 49df817c37..77b06fa757 100644 --- a/Library/Homebrew/os/linux/glibc.rb +++ b/Library/Homebrew/os/linux/glibc.rb @@ -7,6 +7,8 @@ module OS # # @api private module Glibc + extend T::Sig + module_function def system_version @@ -18,6 +20,7 @@ module OS @system_version = Version.new version end + sig { returns(Version) } def minimum_version Version.new "2.13" end diff --git a/Library/Homebrew/os/linux/kernel.rb b/Library/Homebrew/os/linux/kernel.rb index fd535699bc..d74a7412a4 100644 --- a/Library/Homebrew/os/linux/kernel.rb +++ b/Library/Homebrew/os/linux/kernel.rb @@ -7,8 +7,11 @@ module OS # # @api private module Kernel + extend T::Sig + module_function + sig { returns(Version) } def minimum_version Version.new "2.6.32" end diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index c7cd7e1820..6c20bad598 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -10,6 +10,8 @@ require "os/mac/keg" module OS # Helper module for querying system information on macOS. module Mac + extend T::Sig + module_function # rubocop:disable Naming/ConstantName @@ -39,21 +41,21 @@ module OS def latest_sdk_version # TODO: bump version when new Xcode macOS SDK is released - Version.new "10.15" + Version.new "11.0" end def latest_stable_version # TODO: bump version when new macOS is released and also update # references in docs/Installation.md and # https://github.com/Homebrew/install/blob/HEAD/install.sh - Version.new "10.15" + Version.new "11.0" end def outdated_release? # TODO: bump version when new macOS is released and also update # references in docs/Installation.md and # https://github.com/Homebrew/install/blob/HEAD/install.sh - version < "10.13" + version < "10.14" end def prerelease? @@ -81,6 +83,7 @@ module OS @active_developer_dir ||= Utils.popen_read("/usr/bin/xcode-select", "-print-path").strip end + sig { returns(T::Boolean) } def sdk_root_needed? if MacOS::CLT.installed? # If there's no CLT SDK, return false diff --git a/Library/Homebrew/os/mac/keg.rb b/Library/Homebrew/os/mac/keg.rb index b5805975c6..2e2e24dccc 100644 --- a/Library/Homebrew/os/mac/keg.rb +++ b/Library/Homebrew/os/mac/keg.rb @@ -8,6 +8,7 @@ class Keg @require_relocation = true odebug "Changing dylib ID of #{file}\n from #{file.dylib_id}\n to #{id}" MachO::Tools.change_dylib_id(file, id, strict: false) + apply_ad_hoc_signature(file) rescue MachO::MachOError onoe <<~EOS Failed changing dylib ID of #{file} @@ -23,6 +24,7 @@ class Keg @require_relocation = true odebug "Changing install name in #{file}\n from #{old}\n to #{new}" MachO::Tools.change_install_name(file, old, new, strict: false) + apply_ad_hoc_signature(file) rescue MachO::MachOError onoe <<~EOS Failed changing install name in #{file} @@ -31,4 +33,37 @@ class Keg EOS raise end + + def apply_ad_hoc_signature(file) + return if MacOS.version < :big_sur + return unless Hardware::CPU.arm? + + odebug "Codesigning #{file}" + # Use quiet_system to squash notifications about resigning binaries + # which already have valid signatures. + return if quiet_system("codesign", "--sign", "-", "--force", + "--preserve-metadata=entitlements,requirements,flags,runtime", + file) + + # If the codesigning fails, it may be a bug in Apple's codesign utility + # A known workaround is to copy the file to another inode, then move it back + # erasing the previous file. Then sign again. + # + # TODO: remove this once the bug in Apple's codesign utility is fixed + Dir::Tmpname.create("workaround") do |tmppath| + FileUtils.cp file, tmppath + FileUtils.mv tmppath, file, force: true + end + + # Try signing again + odebug "Codesigning (2nd try) #{file}" + return if quiet_system("codesign", "--sign", "-", "--force", + "--preserve-metadata=entitlements,requirements,flags,runtime", + file) + + # If it fails again, error out + onoe <<~EOS + Failed applying an ad-hoc signature to #{file} + EOS + end end diff --git a/Library/Homebrew/os/mac/sdk.rb b/Library/Homebrew/os/mac/sdk.rb index 3a94bc9709..b4a7ff9806 100644 --- a/Library/Homebrew/os/mac/sdk.rb +++ b/Library/Homebrew/os/mac/sdk.rb @@ -92,6 +92,9 @@ module OS # # @api private class XcodeSDKLocator < BaseSDKLocator + extend T::Sig + + sig { returns(Symbol) } def source :xcode end @@ -115,6 +118,9 @@ module OS # # @api private class CLTSDKLocator < BaseSDKLocator + extend T::Sig + + sig { returns(Symbol) } def source :clt end diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index f79ab66384..3ad279dc0d 100644 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -7,20 +7,23 @@ module OS # # @api private module Xcode + extend T::Sig + module_function - DEFAULT_BUNDLE_PATH = Pathname.new("/Applications/Xcode.app").freeze + DEFAULT_BUNDLE_PATH = Pathname("/Applications/Xcode.app").freeze BUNDLE_ID = "com.apple.dt.Xcode" OLD_BUNDLE_ID = "com.apple.Xcode" # Bump these when a new version is available from the App Store and our # CI systems have been updated. # This may be a beta version for a beta macOS. + sig { returns(String) } def latest_version latest_stable = "12.2" case MacOS.version - when "11.0" then "12.2" - when "10.15" then latest_stable + when "11.0" then latest_stable + when "10.15" then "12.2" when "10.14" then "11.3.1" when "10.13" then "10.1" when "10.12" then "9.2" @@ -39,9 +42,10 @@ module OS # without this. Generally this will be the first Xcode release on that # macOS version (which may initially be a beta if that version of macOS is # also in beta). + sig { returns(String) } def minimum_version case MacOS.version - when "11.0" then "12.0" + when "11.0" then "12.2" when "10.15" then "11.0" when "10.14" then "10.2" when "10.13" then "9.0" @@ -93,8 +97,9 @@ module OS end end + sig { returns(Pathname) } def toolchain_path - Pathname.new("#{prefix}/Toolchains/XcodeDefault.xctoolchain") + Pathname("#{prefix}/Toolchains/XcodeDefault.xctoolchain") end def bundle_path @@ -107,6 +112,7 @@ module OS MacOS.app_with_bundle_id(BUNDLE_ID, OLD_BUNDLE_ID) end + sig { returns(T::Boolean) } def installed? !prefix.nil? end @@ -123,6 +129,7 @@ module OS sdk(v)&.path end + sig { returns(String) } def update_instructions if OS::Mac.prerelease? <<~EOS @@ -174,6 +181,7 @@ module OS detect_version_from_clang_version end + sig { returns(String) } def detect_version_from_clang_version return "dunno" if DevelopmentTools.clang_version.null? @@ -181,21 +189,19 @@ module OS # installed CLT version. This is useful as they are packaged # simultaneously so workarounds need to apply to both based on their # comparable version. - latest_stable = "12.0" case (DevelopmentTools.clang_version.to_f * 10).to_i - when 120 then latest_stable - when 110 then "11.5" - when 100 then "10.3" - when 91 then "9.4" - when 90 then "9.2" - when 81 then "8.3" - when 80 then "8.0" - when 73 then "7.3" - when 70 then "7.0" - when 61 then "6.1" - when 60 then "6.0" when 0 then "dunno" - else latest_stable + when 60 then "6.0" + when 61 then "6.1" + when 70 then "7.0" + when 73 then "7.3" + when 80 then "8.0" + when 81 then "8.3" + when 90 then "9.2" + when 91 then "9.4" + when 100 then "10.3" + when 110 then "11.5" + else "12.0" end end @@ -208,6 +214,8 @@ module OS # # @api private module CLT + extend T::Sig + module_function # The original Mavericks CLT package ID @@ -216,6 +224,7 @@ module OS PKG_PATH = "/Library/Developer/CommandLineTools" # Returns true even if outdated tools are installed. + sig { returns(T::Boolean) } def installed? !version.null? end @@ -240,6 +249,7 @@ module OS sdk(v)&.path end + sig { returns(String) } def update_instructions software_update_location = if MacOS.version >= "10.14" "System Preferences" @@ -262,10 +272,10 @@ module OS # Bump these when the new version is distributed through Software Update # and our CI systems have been updated. + sig { returns(String) } def latest_clang_version case MacOS.version - when "11.0" then "1200.0.32.27" - when "10.15" then "1200.0.32.27" + when "11.0", "10.15" then "1200.0.32.27" when "10.14" then "1100.0.33.17" when "10.13" then "1000.10.44.2" when "10.12" then "900.0.39.2" @@ -278,6 +288,7 @@ module OS # Bump these if things are badly broken (e.g. no SDK for this macOS) # without this. Generally this will be the first stable CLT release on # that macOS version. + sig { returns(String) } def minimum_version case MacOS.version when "11.0" then "12.0.0" @@ -295,6 +306,7 @@ module OS version < minimum_version end + sig { returns(T::Boolean) } def outdated? clang_version = detect_clang_version return false unless clang_version diff --git a/Library/Homebrew/os/mac/xquartz.rb b/Library/Homebrew/os/mac/xquartz.rb index c056a27529..00819de600 100644 --- a/Library/Homebrew/os/mac/xquartz.rb +++ b/Library/Homebrew/os/mac/xquartz.rb @@ -7,9 +7,11 @@ module OS # # @api private module XQuartz + extend T::Sig + module_function - DEFAULT_BUNDLE_PATH = Pathname.new("Applications/Utilities/XQuartz.app").freeze + DEFAULT_BUNDLE_PATH = Pathname("Applications/Utilities/XQuartz.app").freeze FORGE_BUNDLE_ID = "org.macosforge.xquartz.X11" FORGE_PKG_ID = "org.macosforge.xquartz.pkg" @@ -52,6 +54,7 @@ module OS end end + sig { returns(String) } def minimum_version # Update this a little later than latest_version to give people # time to upgrade. @@ -59,6 +62,7 @@ module OS end # @see https://www.xquartz.org/releases/index.html + sig { returns(String) } def latest_version "2.7.11" end diff --git a/Library/Homebrew/patch.rb b/Library/Homebrew/patch.rb index 61d00d6a08..1157c61005 100644 --- a/Library/Homebrew/patch.rb +++ b/Library/Homebrew/patch.rb @@ -60,6 +60,8 @@ end # # @api private class EmbeddedPatch + extend T::Sig + attr_writer :owner attr_reader :strip @@ -67,6 +69,7 @@ class EmbeddedPatch @strip = strip end + sig { returns(T::Boolean) } def external? false end @@ -79,6 +82,7 @@ class EmbeddedPatch Utils.safe_popen_write("patch", *args) { |p| p.write(data) } end + sig { returns(String) } def inspect "#<#{self.class.name}: #{strip.inspect}>" end @@ -88,6 +92,8 @@ end # # @api private class DATAPatch < EmbeddedPatch + extend T::Sig + attr_accessor :path def initialize(strip) @@ -95,6 +101,7 @@ class DATAPatch < EmbeddedPatch @path = nil end + sig { returns(String) } def contents data = +"" path.open("rb") do |f| @@ -128,6 +135,8 @@ end # # @api private class ExternalPatch + extend T::Sig + extend Forwardable attr_reader :resource, :strip @@ -141,6 +150,7 @@ class ExternalPatch @resource = Resource::PatchResource.new(&block) end + sig { returns(T::Boolean) } def external? true end @@ -181,6 +191,7 @@ class ExternalPatch raise BuildError.new(f, cmd, args, ENV.to_hash) end + sig { returns(String) } def inspect "#<#{self.class.name}: #{strip.inspect} #{url.inspect}>" end diff --git a/Library/Homebrew/reinstall.rb b/Library/Homebrew/reinstall.rb index b763cd03b5..f75867ed7e 100644 --- a/Library/Homebrew/reinstall.rb +++ b/Library/Homebrew/reinstall.rb @@ -27,21 +27,25 @@ module Homebrew build_from_source_formulae = args.build_from_source_formulae build_from_source_formulae << f.full_name if build_from_source - fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?, - build_from_source_formulae: build_from_source_formulae, - debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?) - fi.options = options - fi.force = args.force? - fi.keep_tmp = args.keep_tmp? - fi.build_bottle = args.build_bottle? - fi.interactive = args.interactive? - fi.git = args.git? - fi.link_keg ||= keg_was_linked if keg_had_linked_opt - if tab - fi.build_bottle ||= tab.built_bottle? - fi.installed_as_dependency = tab.installed_as_dependency - fi.installed_on_request = tab.installed_on_request - end + fi = FormulaInstaller.new( + f, + **{ + options: options, + link_keg: keg_had_linked_opt ? keg_was_linked : nil, + installed_as_dependency: tab&.installed_as_dependency, + installed_on_request: tab&.installed_on_request, + build_bottle: args.build_bottle? || tab&.built_bottle?, + force_bottle: args.force_bottle?, + build_from_source_formulae: build_from_source_formulae, + git: args.git?, + interactive: args.interactive?, + keep_tmp: args.keep_tmp?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose?, + }.compact, + ) fi.prelude fi.fetch diff --git a/Library/Homebrew/requirement.rb b/Library/Homebrew/requirement.rb index 1f10e4aee7..5078ac7bd7 100644 --- a/Library/Homebrew/requirement.rb +++ b/Library/Homebrew/requirement.rb @@ -12,6 +12,8 @@ require "build_environment" # # @api private class Requirement + extend T::Sig + include Dependable attr_reader :tags, :name, :cask, :download @@ -35,6 +37,7 @@ class Requirement end # The message to show when the requirement is not met. + sig { returns(String) } def message _, _, class_name = self.class.to_s.rpartition "::" s = "#{class_name} unsatisfied!\n" @@ -79,7 +82,7 @@ class Requirement return unless @satisfied_result.is_a?(Pathname) parent = @satisfied_result.resolved_path.parent - if parent.to_s =~ %r{^#{Regexp.escape(HOMEBREW_CELLAR)}/([\w+-.@]+)/[^/]+/(s?bin)/?$} + if parent.to_s =~ %r{^#{Regexp.escape(HOMEBREW_CELLAR)}/([\w+-.@]+)/[^/]+/(s?bin)/?$}o parent = HOMEBREW_PREFIX/"opt/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}" end parent @@ -121,6 +124,7 @@ class Requirement name.hash ^ tags.hash end + sig { returns(String) } def inspect "#<#{self.class.name}: #{tags.inspect}>" end @@ -155,6 +159,8 @@ class Requirement end class << self + extend T::Sig + include BuildEnvironment::DSL attr_reader :env_proc, :build @@ -162,14 +168,14 @@ class Requirement attr_rw :fatal, :cask, :download def satisfy(options = nil, &block) - return @satisfied if options.nil? && !block_given? + return @satisfied if options.nil? && !block options = {} if options.nil? @satisfied = Satisfier.new(options, &block) end def env(*settings, &block) - if block_given? + if block @env_proc = block else super @@ -230,9 +236,9 @@ class Requirement reqs end - def prune?(dependent, req, &_block) + def prune?(dependent, req, &block) catch(:prune) do - if block_given? + if block yield dependent, req elsif req.optional? || req.recommended? prune unless dependent.build.with?(req) @@ -241,6 +247,7 @@ class Requirement end # Used to prune requirements when calling expand with a block. + sig { void } def prune throw(:prune, true) end diff --git a/Library/Homebrew/requirements/arch_requirement.rb b/Library/Homebrew/requirements/arch_requirement.rb index ec6a213174..8c65b44fa6 100644 --- a/Library/Homebrew/requirements/arch_requirement.rb +++ b/Library/Homebrew/requirements/arch_requirement.rb @@ -7,6 +7,8 @@ require "requirement" # # @api private class ArchRequirement < Requirement + extend T::Sig + fatal true attr_reader :arch @@ -24,6 +26,7 @@ class ArchRequirement < Requirement end end + sig { returns(String) } def message "The #{@arch} architecture is required for this software." end @@ -32,6 +35,7 @@ class ArchRequirement < Requirement "#<#{self.class.name}: arch=#{@arch.to_s.inspect} #{tags.inspect}>" end + sig { returns(String) } def display_s "#{@arch} architecture" end diff --git a/Library/Homebrew/requirements/codesign_requirement.rb b/Library/Homebrew/requirements/codesign_requirement.rb index 54fb9352a2..06caebda71 100644 --- a/Library/Homebrew/requirements/codesign_requirement.rb +++ b/Library/Homebrew/requirements/codesign_requirement.rb @@ -5,6 +5,8 @@ # # @api private class CodesignRequirement < Requirement + extend T::Sig + fatal true def initialize(tags) @@ -26,6 +28,7 @@ class CodesignRequirement < Requirement end end + sig { returns(String) } def message message = "#{@identity} identity must be available to build with #{@with}" message += ":\n#{@url}" if @url.present? diff --git a/Library/Homebrew/requirements/java_requirement.rb b/Library/Homebrew/requirements/java_requirement.rb index 3edab63aa8..fdee4f4e03 100644 --- a/Library/Homebrew/requirements/java_requirement.rb +++ b/Library/Homebrew/requirements/java_requirement.rb @@ -7,6 +7,8 @@ require "language/java" # # @api private class JavaRequirement < Requirement + extend T::Sig + fatal true attr_reader :java_home, :version @@ -37,6 +39,7 @@ class JavaRequirement < Requirement @cask = suggestion.token end + sig { returns(String) } def message version_string = " #{@version}" if @version s = "Java#{version_string} is required for this software.\n" @@ -44,6 +47,7 @@ class JavaRequirement < Requirement s end + sig { returns(String) } def inspect "#<#{self.class.name}: version=#{@version.inspect} #{tags.inspect}>" end @@ -64,6 +68,9 @@ class JavaRequirement < Requirement private CaskSuggestion = Struct.new(:token, :title) do + extend T::Sig + + sig { returns(String) } def to_str title_string = " #{title}" if title <<~EOS diff --git a/Library/Homebrew/requirements/linux_requirement.rb b/Library/Homebrew/requirements/linux_requirement.rb index 1a0e496282..410c39bcc4 100644 --- a/Library/Homebrew/requirements/linux_requirement.rb +++ b/Library/Homebrew/requirements/linux_requirement.rb @@ -5,10 +5,13 @@ # # @api private class LinuxRequirement < Requirement + extend T::Sig + fatal true satisfy(build_env: false) { OS.linux? } + sig { returns(String) } def message "Linux is required for this software." end diff --git a/Library/Homebrew/requirements/macos_requirement.rb b/Library/Homebrew/requirements/macos_requirement.rb index c00750b9a2..52b1e84b20 100644 --- a/Library/Homebrew/requirements/macos_requirement.rb +++ b/Library/Homebrew/requirements/macos_requirement.rb @@ -7,6 +7,8 @@ require "requirement" # # @api private class MacOSRequirement < Requirement + extend T::Sig + fatal true attr_reader :comparator, :version @@ -66,14 +68,22 @@ class MacOSRequirement < Requirement end end + sig { returns(String) } def inspect "#<#{self.class.name}: version#{@comparator}#{@version.to_s.inspect} #{tags.inspect}>" end + sig { returns(String) } def display_s - return "macOS" unless version_specified? - - "macOS #{@comparator} #{@version}" + if version_specified? + if @version.respond_to?(:to_ary) + "macOS #{@comparator} #{version.join(" / ")}" + else + "macOS #{@comparator} #{@version}" + end + else + "macOS" + end end def to_json(*args) diff --git a/Library/Homebrew/requirements/tuntap_requirement.rb b/Library/Homebrew/requirements/tuntap_requirement.rb index 40075a947b..3599dcff4c 100644 --- a/Library/Homebrew/requirements/tuntap_requirement.rb +++ b/Library/Homebrew/requirements/tuntap_requirement.rb @@ -7,10 +7,13 @@ require "requirement" # # @api private class TuntapRequirement < Requirement + extend T::Sig + fatal true cask "tuntap" satisfy(build_env: false) { self.class.binary_tuntap_installed? } + sig { returns(T::Boolean) } def self.binary_tuntap_installed? %w[ /Library/Extensions/tun.kext diff --git a/Library/Homebrew/requirements/x11_requirement.rb b/Library/Homebrew/requirements/x11_requirement.rb index 4418f2f8ef..d55a0ef984 100644 --- a/Library/Homebrew/requirements/x11_requirement.rb +++ b/Library/Homebrew/requirements/x11_requirement.rb @@ -7,6 +7,8 @@ require "requirement" # # @api private class X11Requirement < Requirement + extend T::Sig + include Comparable fatal true @@ -16,10 +18,12 @@ class X11Requirement < Requirement env { ENV.x11 } + sig { returns(String) } def min_version "1.12.2" end + sig { returns(String) } def min_xdpyinfo_version "1.3.0" end @@ -38,6 +42,7 @@ class X11Requirement < Requirement false end + sig { returns(String) } def message "X11 is required for this software, either Xorg #{min_version} or " \ "xdpyinfo #{min_xdpyinfo_version}, or newer. #{super}" @@ -48,6 +53,11 @@ class X11Requirement < Requirement 0 end + + sig { returns(String) } + def inspect + "#<#{self.class.name}: #{tags.inspect}>" + end end require "extend/os/requirements/x11_requirement" diff --git a/Library/Homebrew/requirements/xcode_requirement.rb b/Library/Homebrew/requirements/xcode_requirement.rb index b3e6973cfd..775d62fc56 100644 --- a/Library/Homebrew/requirements/xcode_requirement.rb +++ b/Library/Homebrew/requirements/xcode_requirement.rb @@ -7,6 +7,8 @@ require "requirement" # # @api private class XcodeRequirement < Requirement + extend T::Sig + fatal true attr_reader :version @@ -25,6 +27,7 @@ class XcodeRequirement < Requirement MacOS::Xcode.version >= @version end + sig { returns(String) } def message version = " #{@version}" if @version message = <<~EOS @@ -45,6 +48,7 @@ class XcodeRequirement < Requirement end end + sig { returns(String) } def inspect "#<#{self.class.name}: version>=#{@version.inspect} #{tags.inspect}>" end diff --git a/Library/Homebrew/resource.rb b/Library/Homebrew/resource.rb index f9c536467c..68c237471a 100644 --- a/Library/Homebrew/resource.rb +++ b/Library/Homebrew/resource.rb @@ -32,7 +32,7 @@ class Resource @checksum = nil @using = nil @patches = [] - instance_eval(&block) if block_given? + instance_eval(&block) if block end def owner=(owner) @@ -253,6 +253,8 @@ end # # @api private class ResourceStageContext + extend T::Sig + extend Forwardable # The {Resource} that is being staged. @@ -268,6 +270,7 @@ class ResourceStageContext @staging = staging end + sig { returns(String) } def to_s "<#{self.class}: resource=#{resource} staging=#{staging}>" end diff --git a/Library/Homebrew/resource_auditor.rb b/Library/Homebrew/resource_auditor.rb new file mode 100644 index 0000000000..f386eb511a --- /dev/null +++ b/Library/Homebrew/resource_auditor.rb @@ -0,0 +1,118 @@ +# typed: false +# frozen_string_literal: true + +module Homebrew + # Auditor for checking common violations in {Resource}s. + # + # @api private + class ResourceAuditor + attr_reader :name, :version, :checksum, :url, :mirrors, :using, :specs, :owner, :spec_name, :problems + + def initialize(resource, spec_name, options = {}) + @name = resource.name + @version = resource.version + @checksum = resource.checksum + @url = resource.url + @mirrors = resource.mirrors + @using = resource.using + @specs = resource.specs + @owner = resource.owner + @spec_name = spec_name + @online = options[:online] + @strict = options[:strict] + @problems = [] + end + + def audit + audit_version + audit_download_strategy + audit_urls + self + end + + def audit_version + if version.nil? + problem "missing version" + elsif !version.detected_from_url? + version_text = version + version_url = Version.detect(url, **specs) + if version_url.to_s == version_text.to_s && version.instance_of?(Version) + problem "version #{version_text} is redundant with version scanned from URL" + end + end + end + + def audit_download_strategy + url_strategy = DownloadStrategyDetector.detect(url) + + if (using == :git || url_strategy == GitDownloadStrategy) && specs[:tag] && !specs[:revision] + problem "Git should specify :revision when a :tag is specified." + end + + return unless using + + if using == :cvs + mod = specs[:module] + + problem "Redundant :module value in URL" if mod == name + + if url.match?(%r{:[^/]+$}) + mod = url.split(":").last + + if mod == name + problem "Redundant CVS module appended to URL" + else + problem "Specify CVS module as `:module => \"#{mod}\"` instead of appending it to the URL" + end + end + end + + return unless url_strategy == DownloadStrategyDetector.detect("", using) + + problem "Redundant :using value in URL" + end + + def self.curl_openssl_and_deps + @curl_openssl_and_deps ||= begin + formulae_names = ["curl", "openssl"] + formulae_names += formulae_names.flat_map do |f| + Formula[f].recursive_dependencies.map(&:name) + end + formulae_names.uniq + rescue FormulaUnavailableError + [] + end + end + + def audit_urls + return unless @online + + urls = [url] + mirrors + urls.each do |url| + next if !@strict && mirrors.include?(url) + + strategy = DownloadStrategyDetector.detect(url, using) + if strategy <= CurlDownloadStrategy && !url.start_with?("file") + # A `brew mirror`'ed URL is usually not yet reachable at the time of + # pull request. + next if url.match?(%r{^https://dl.bintray.com/homebrew/mirror/}) + + if http_content_problem = curl_check_http_content(url) + problem http_content_problem + end + elsif strategy <= GitDownloadStrategy + problem "The URL #{url} is not a valid git URL" unless Utils::Git.remote_exists? url + elsif strategy <= SubversionDownloadStrategy + next unless DevelopmentTools.subversion_handles_most_https_certificates? + next unless Utils::Svn.available? + + problem "The URL #{url} is not a valid svn URL" unless Utils::Svn.remote_exists? url + end + end + end + + def problem(text) + @problems << text + end + end +end diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb index e5c5651439..24a89b54ae 100644 --- a/Library/Homebrew/rubocops.rb +++ b/Library/Homebrew/rubocops.rb @@ -3,6 +3,8 @@ require_relative "load_path" +require "utils/sorbet" + require "rubocop-performance" require "rubocop-rspec" require "rubocop-sorbet" diff --git a/Library/Homebrew/rubocops/cask/ast/cask_header.rb b/Library/Homebrew/rubocops/cask/ast/cask_header.rb index a869967a5b..addb8a718c 100644 --- a/Library/Homebrew/rubocops/cask/ast/cask_header.rb +++ b/Library/Homebrew/rubocops/cask/ast/cask_header.rb @@ -7,6 +7,8 @@ module RuboCop # This class wraps the AST method node that represents the cask header. It # includes various helper methods to aid cops in their analysis. class CaskHeader + extend T::Sig + def initialize(method_node) @method_node = method_node end @@ -25,6 +27,7 @@ module RuboCop @source_range ||= method_node.loc.expression end + sig { returns(String) } def preferred_header_str "cask '#{cask_token}'" end diff --git a/Library/Homebrew/rubocops/cask/extend/string.rb b/Library/Homebrew/rubocops/cask/extend/string.rb index e89bed3af4..f4e4ee3be0 100644 --- a/Library/Homebrew/rubocops/cask/extend/string.rb +++ b/Library/Homebrew/rubocops/cask/extend/string.rb @@ -3,6 +3,9 @@ # Utility method extensions for String. class String + extend T::Sig + + sig { returns(String) } def undent gsub(/^.{#{(slice(/^ +/) || '').length}}/, "") end diff --git a/Library/Homebrew/rubocops/cask/no_dsl_version.rb b/Library/Homebrew/rubocops/cask/no_dsl_version.rb index 2d2aca942b..7866e52fe6 100644 --- a/Library/Homebrew/rubocops/cask/no_dsl_version.rb +++ b/Library/Homebrew/rubocops/cask/no_dsl_version.rb @@ -19,6 +19,8 @@ module RuboCop # ... # end class NoDslVersion < Cop + extend T::Sig + extend Forwardable include CaskHelp @@ -56,6 +58,7 @@ module RuboCop message: error_msg) end + sig { returns(String) } def error_msg format(MESSAGE, preferred: preferred_header_str, current: header_str) end diff --git a/Library/Homebrew/rubocops/components_order.rb b/Library/Homebrew/rubocops/components_order.rb index f76351fc0e..7f6613799c 100644 --- a/Library/Homebrew/rubocops/components_order.rb +++ b/Library/Homebrew/rubocops/components_order.rb @@ -38,6 +38,8 @@ module RuboCop [{ name: :keg_only, type: :method_call }], [{ name: :option, type: :method_call }], [{ name: :deprecated_option, type: :method_call }], + [{ name: :disable!, type: :method_call }], + [{ name: :deprecate!, type: :method_call }], [{ name: :depends_on, type: :method_call }], [{ name: :uses_from_macos, type: :method_call }], [{ name: :on_macos, type: :block_call }], diff --git a/Library/Homebrew/rubocops/homepage.rb b/Library/Homebrew/rubocops/homepage.rb index c8f802a2c1..c41c02d041 100644 --- a/Library/Homebrew/rubocops/homepage.rb +++ b/Library/Homebrew/rubocops/homepage.rb @@ -23,16 +23,6 @@ module RuboCop end case homepage - # Check for http:// GitHub homepage URLs, https:// is preferred. - # Note: only check homepages that are repo pages, not *.github.com hosts - when %r{^http://github.com/} - problem "Please use https:// for #{homepage}" - - # Savannah has full SSL/TLS support but no auto-redirect. - # Doesn't apply to the download URLs, only the homepage. - when %r{^http://savannah.nongnu.org/} - problem "Please use https:// for #{homepage}" - # Freedesktop is complicated to handle - It has SSL/TLS, but only on certain subdomains. # To enable https Freedesktop change the URL from http://project.freedesktop.org/wiki to # https://wiki.freedesktop.org/project_name. @@ -48,14 +38,6 @@ module RuboCop when %r{^https?://code\.google\.com/p/[^/]+[^/]$} problem "#{homepage} should end with a slash" - # People will run into mixed content sometimes, but we should enforce and then add - # exemptions as they are discovered. Treat mixed content on homepages as a bug. - # Justify each exemptions with a code comment so we can keep track here. - - when %r{^http://[^/]*\.github\.io/}, - %r{^http://[^/]*\.sourceforge\.io/} - problem "Please use https:// for #{homepage}" - when %r{^http://([^/]*)\.(sf|sourceforge)\.net(/|$)} problem "#{homepage} should be `https://#{Regexp.last_match(1)}.sourceforge.io/`" @@ -67,15 +49,28 @@ module RuboCop offending_node(parameters(homepage_node).first) problem "GitHub homepages (`#{homepage}`) should not end with .git" - # There's an auto-redirect here, but this mistake is incredibly common too. - # Only applies to the homepage and subdomains for now, not the FTP URLs. - when %r{^http://((?:build|cloud|developer|download|extensions|git| - glade|help|library|live|nagios|news|people| - projects|rt|static|wiki|www)\.)?gnome\.org}x - problem "Please use https:// for #{homepage}" - + # People will run into mixed content sometimes, but we should enforce and then add + # exemptions as they are discovered. Treat mixed content on homepages as a bug. + # Justify each exemptions with a code comment so we can keep track here. + # # Compact the above into this list as we're able to remove detailed notations, etc over time. - when %r{^http://[^/]*\.apache\.org}, + when + # Check for http:// GitHub homepage URLs, https:// is preferred. + # Note: only check homepages that are repo pages, not *.github.com hosts + %r{^http://github.com/}, + %r{^http://[^/]*\.github\.io/}, + + # Savannah has full SSL/TLS support but no auto-redirect. + # Doesn't apply to the download URLs, only the homepage. + %r{^http://savannah.nongnu.org/}, + + %r{^http://[^/]*\.sourceforge\.io/}, + # There's an auto-redirect here, but this mistake is incredibly common too. + # Only applies to the homepage and subdomains for now, not the FTP URLs. + %r{^http://((?:build|cloud|developer|download|extensions|git| + glade|help|library|live|nagios|news|people| + projects|rt|static|wiki|www)\.)?gnome\.org}x, + %r{^http://[^/]*\.apache\.org}, %r{^http://packages\.debian\.org}, %r{^http://wiki\.freedesktop\.org/}, %r{^http://((?:www)\.)?gnupg\.org/}, diff --git a/Library/Homebrew/rubocops/patches.rb b/Library/Homebrew/rubocops/patches.rb index 8d85bd9f93..57c746df52 100644 --- a/Library/Homebrew/rubocops/patches.rb +++ b/Library/Homebrew/rubocops/patches.rb @@ -9,6 +9,8 @@ module RuboCop module FormulaAudit # This cop audits `patch`es in formulae. class Patches < FormulaCop + extend T::Sig + def audit_formula(node, _class_node, _parent_class_node, body) @full_source_content = source_buffer(node).source @@ -121,6 +123,7 @@ module RuboCop (send nil? :patch (:sym :DATA)) AST + sig { returns(T::Boolean) } def patch_end? /^__END__$/.match?(@full_source_content) end diff --git a/Library/Homebrew/rubocops/urls.rb b/Library/Homebrew/rubocops/urls.rb index 3c7b855da0..62e347666b 100644 --- a/Library/Homebrew/rubocops/urls.rb +++ b/Library/Homebrew/rubocops/urls.rb @@ -294,6 +294,8 @@ module RuboCop # # @api private class PyPiUrls < FormulaCop + extend T::Sig + def audit_formula(_node, _class_node, _parent_class_node, body_node) urls = find_every_func_call_by_name(body_node, :url) mirrors = find_every_func_call_by_name(body_node, :mirror) @@ -312,6 +314,7 @@ module RuboCop end end + sig { params(url: String).returns(String) } def get_pypi_url(url) package_file = File.basename(url) package_name = package_file.match(/^(.+)-[a-z0-9.]+$/)[1] diff --git a/Library/Homebrew/sandbox.rb b/Library/Homebrew/sandbox.rb index 54d0a76682..2f79ae6a86 100644 --- a/Library/Homebrew/sandbox.rb +++ b/Library/Homebrew/sandbox.rb @@ -8,13 +8,17 @@ require "tempfile" # # @api private class Sandbox + extend T::Sig + SANDBOX_EXEC = "/usr/bin/sandbox-exec" private_constant :SANDBOX_EXEC + sig { returns(T::Boolean) } def self.available? OS.mac? && File.executable?(SANDBOX_EXEC) end + sig { void } def initialize @profile = SandboxProfile.new end @@ -146,6 +150,8 @@ class Sandbox # Configuration profile for a sandbox. class SandboxProfile + extend T::Sig + SEATBELT_ERB = <<~ERB (version 1) (debug deny) ; log all denied operations to /var/log/system.log @@ -169,6 +175,7 @@ class Sandbox attr_reader :rules + sig { void } def initialize @rules = [] end diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index 8a6ed260e6..f5f817ba05 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -14,6 +14,8 @@ require "global" require "os/mac/version" class SoftwareSpec + extend T::Sig + extend Forwardable PREDEFINED_OPTIONS = { @@ -78,6 +80,7 @@ class SoftwareSpec @bottle_disable_reason.unneeded? end + sig { returns(T::Boolean) } def bottle_disabled? @bottle_disable_reason ? true : false end @@ -104,7 +107,7 @@ class SoftwareSpec end def resource(name, klass = Resource, &block) - if block_given? + if block raise DuplicateResourceError, name if resource_defined?(name) res = klass.new(name, &block) @@ -247,6 +250,8 @@ end class Bottle class Filename + extend T::Sig + attr_reader :name, :version, :tag, :rebuild def self.create(formula, tag, rebuild) @@ -260,11 +265,13 @@ class Bottle @rebuild = rebuild end + sig { returns(String) } def to_s "#{name}--#{version}#{extname}" end alias to_str to_s + sig { returns(String) } def json "#{name}--#{version}.#{tag}.bottle.json" end @@ -273,6 +280,7 @@ class Bottle ERB::Util.url_encode("#{name}-#{version}#{extname}") end + sig { returns(String) } def extname s = rebuild.positive? ? ".#{rebuild}" : "" ".#{tag}.bottle#{s}.tar.gz" @@ -327,12 +335,15 @@ class Bottle end class BottleSpecification + extend T::Sig + DEFAULT_PREFIX = Homebrew::DEFAULT_PREFIX attr_rw :prefix, :cellar, :rebuild attr_accessor :tap attr_reader :checksum, :collector, :root_url_specs + sig { void } def initialize @rebuild = 0 @prefix = Homebrew::DEFAULT_PREFIX @@ -355,6 +366,7 @@ class BottleSpecification end # Does the {Bottle} this {BottleSpecification} belongs to need to be relocated? + sig { returns(T::Boolean) } def skip_relocation? cellar == :any_skip_relocation end diff --git a/Library/Homebrew/sorbet/plugins/attr_predicate.rb b/Library/Homebrew/sorbet/plugins/attr_predicate.rb new file mode 100644 index 0000000000..2559705d5d --- /dev/null +++ b/Library/Homebrew/sorbet/plugins/attr_predicate.rb @@ -0,0 +1,13 @@ +# typed: strict +# frozen_string_literal: true + +source = ARGV[5] + +source.scan(/:([^?]+\?)/).flatten.each do |method| + puts <<~RUBY + # typed: strict + + sig { returns(T::Boolean) } + def #{method}; end + RUBY +end diff --git a/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2020.0512.rbi b/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2020.1104.rbi similarity index 90% rename from Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2020.0512.rbi rename to Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2020.1104.rbi index 0a248f7d65..c40bda7674 100644 --- a/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2020.0512.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2020.1104.rbi @@ -1,6 +1,6 @@ # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `mime-types-data` gem. -# Please instead update this file by running `tapioca generate --exclude json`. +# Please instead update this file by running `tapioca sync`. # typed: true @@ -36,8 +36,8 @@ class MIME::Types def count; end def each; end def logger; end - def logger=(_); end - def new(*_); end + def logger=(_arg0); end + def new(*_arg0); end def of(filename); end def type_for(filename); end @@ -59,11 +59,11 @@ class MIME::Types::Cache < ::Struct def version=(_); end class << self - def [](*_); end + def [](*_arg0); end def inspect; end def load(cache_file = T.unsafe(nil)); end def members; end - def new(*_); end + def new(*_arg0); end def save(types = T.unsafe(nil), cache_file = T.unsafe(nil)); end end end diff --git a/Library/Homebrew/sorbet/rbi/gems/rspec-sorbet@1.6.0-7390691c90f7267b9d7dc28e8f5b7150840f9e48.rbi b/Library/Homebrew/sorbet/rbi/gems/rspec-sorbet@1.6.0-7390691c90f7267b9d7dc28e8f5b7150840f9e48.rbi new file mode 100644 index 0000000000..bbc503d5d5 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/rspec-sorbet@1.6.0-7390691c90f7267b9d7dc28e8f5b7150840f9e48.rbi @@ -0,0 +1,8 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `rspec-sorbet` gem. +# Please instead update this file by running `tapioca sync`. + +# typed: true + +# THIS IS AN EMPTY RBI FILE. +# see https://github.com/Shopify/tapioca/blob/master/README.md#manual-gem-requires diff --git a/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.8.1.rbi b/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.9.0.rbi similarity index 70% rename from Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.8.1.rbi rename to Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.9.0.rbi index b6be536070..3d47926428 100644 --- a/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.8.1.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.9.0.rbi @@ -17,7 +17,7 @@ class RuboCop::Cop::Performance::AncestorsInclude < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) - def ancestors_include_candidate?(node = T.unsafe(nil)); end + def ancestors_include_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -27,10 +27,32 @@ end RuboCop::Cop::Performance::AncestorsInclude::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::AncestorsInclude::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Performance::ArraySemiInfiniteRangeSlice < ::RuboCop::Cop::Base + include(::RuboCop::Cop::RangeHelp) + extend(::RuboCop::Cop::AutoCorrector) + extend(::RuboCop::Cop::TargetRubyVersion) + + def endless_range?(param0 = T.unsafe(nil)); end + def endless_range_slice?(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def correction(receiver, range_node); end +end + +RuboCop::Cop::Performance::ArraySemiInfiniteRangeSlice::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Performance::ArraySemiInfiniteRangeSlice::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Set) + +RuboCop::Cop::Performance::ArraySemiInfiniteRangeSlice::SLICE_METHODS = T.let(T.unsafe(nil), Set) + class RuboCop::Cop::Performance::BigDecimalWithNumericArgument < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def big_decimal_with_numeric_argument?(node = T.unsafe(nil)); end + def big_decimal_with_numeric_argument?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -40,12 +62,14 @@ end RuboCop::Cop::Performance::BigDecimalWithNumericArgument::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::BigDecimalWithNumericArgument::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::BindCall < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) extend(::RuboCop::Cop::TargetRubyVersion) - def bind_with_call_method?(node = T.unsafe(nil)); end + def bind_with_call_method?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -57,20 +81,34 @@ end RuboCop::Cop::Performance::BindCall::MSG = T.let(T.unsafe(nil), String) -class RuboCop::Cop::Performance::Caller < ::RuboCop::Cop::Base - def caller_with_scope_method?(node = T.unsafe(nil)); end +RuboCop::Cop::Performance::BindCall::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Performance::BlockGivenWithExplicitBlock < ::RuboCop::Cop::Base + extend(::RuboCop::Cop::AutoCorrector) + def on_send(node); end - def slow_caller?(node = T.unsafe(nil)); end + def reassigns_block_arg?(param0 = T.unsafe(nil), param1); end +end + +RuboCop::Cop::Performance::BlockGivenWithExplicitBlock::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Performance::BlockGivenWithExplicitBlock::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Performance::Caller < ::RuboCop::Cop::Base + extend(::RuboCop::Cop::AutoCorrector) + + def caller_with_scope_method?(param0 = T.unsafe(nil)); end + def on_send(node); end + def slow_caller?(param0 = T.unsafe(nil)); end private def int_value(node); end - def message(node); end end -RuboCop::Cop::Performance::Caller::MSG_BRACE = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Caller::MSG = T.let(T.unsafe(nil), String) -RuboCop::Cop::Performance::Caller::MSG_FIRST = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Caller::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) class RuboCop::Cop::Performance::CaseWhenSplat < ::RuboCop::Cop::Base include(::RuboCop::Cop::Alignment) @@ -103,9 +141,9 @@ RuboCop::Cop::Performance::CaseWhenSplat::MSG = T.let(T.unsafe(nil), String) class RuboCop::Cop::Performance::Casecmp < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def downcase_downcase(node = T.unsafe(nil)); end - def downcase_eq(node = T.unsafe(nil)); end - def eq_downcase(node = T.unsafe(nil)); end + def downcase_downcase(param0 = T.unsafe(nil)); end + def downcase_eq(param0 = T.unsafe(nil)); end + def eq_downcase(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -119,10 +157,12 @@ RuboCop::Cop::Performance::Casecmp::CASE_METHODS = T.let(T.unsafe(nil), Array) RuboCop::Cop::Performance::Casecmp::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Casecmp::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::ChainArrayAllocation < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) - def flat_map_candidate?(node = T.unsafe(nil)); end + def flat_map_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end end @@ -137,8 +177,8 @@ RuboCop::Cop::Performance::ChainArrayAllocation::RETURNS_NEW_ARRAY_WHEN_NO_BLOCK RuboCop::Cop::Performance::ChainArrayAllocation::RETURN_NEW_ARRAY_WHEN_ARGS = T.let(T.unsafe(nil), String) class RuboCop::Cop::Performance::CollectionLiteralInLoop < ::RuboCop::Cop::Base - def enumerable_loop?(node = T.unsafe(nil)); end - def kernel_loop?(node = T.unsafe(nil)); end + def enumerable_loop?(param0 = T.unsafe(nil)); end + def kernel_loop?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -174,9 +214,9 @@ class RuboCop::Cop::Performance::CompareWithBlock < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) - def compare?(node = T.unsafe(nil)); end + def compare?(param0 = T.unsafe(nil)); end def on_block(node); end - def replaceable_body?(node = T.unsafe(nil), param1, param2); end + def replaceable_body?(param0 = T.unsafe(nil), param1, param2); end private @@ -187,11 +227,25 @@ end RuboCop::Cop::Performance::CompareWithBlock::MSG = T.let(T.unsafe(nil), String) +class RuboCop::Cop::Performance::ConstantRegexp < ::RuboCop::Cop::Base + extend(::RuboCop::Cop::AutoCorrector) + + def on_regexp(node); end + def regexp_escape?(param0 = T.unsafe(nil)); end + + private + + def include_interpolated_const?(node); end + def within_const_assignment?(node); end +end + +RuboCop::Cop::Performance::ConstantRegexp::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Performance::Count < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) - def count_candidate?(node = T.unsafe(nil)); end + def count_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -203,12 +257,14 @@ end RuboCop::Cop::Performance::Count::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Count::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::DeletePrefix < ::RuboCop::Cop::Base include(::RuboCop::Cop::RegexpMetacharacter) extend(::RuboCop::Cop::AutoCorrector) extend(::RuboCop::Cop::TargetRubyVersion) - def delete_prefix_candidate?(node = T.unsafe(nil)); end + def delete_prefix_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end end @@ -216,12 +272,14 @@ RuboCop::Cop::Performance::DeletePrefix::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Performance::DeletePrefix::PREFERRED_METHODS = T.let(T.unsafe(nil), Hash) +RuboCop::Cop::Performance::DeletePrefix::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::DeleteSuffix < ::RuboCop::Cop::Base include(::RuboCop::Cop::RegexpMetacharacter) extend(::RuboCop::Cop::AutoCorrector) extend(::RuboCop::Cop::TargetRubyVersion) - def delete_suffix_candidate?(node = T.unsafe(nil)); end + def delete_suffix_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end end @@ -229,10 +287,12 @@ RuboCop::Cop::Performance::DeleteSuffix::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Performance::DeleteSuffix::PREFERRED_METHODS = T.let(T.unsafe(nil), Hash) +RuboCop::Cop::Performance::DeleteSuffix::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::Detect < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def detect_candidate?(node = T.unsafe(nil)); end + def detect_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -254,14 +314,16 @@ RuboCop::Cop::Performance::Detect::INDEX_REVERSE_MSG = T.let(T.unsafe(nil), Stri RuboCop::Cop::Performance::Detect::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Detect::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + RuboCop::Cop::Performance::Detect::REVERSE_MSG = T.let(T.unsafe(nil), String) class RuboCop::Cop::Performance::DoubleStartEndWith < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def check_with_active_support_aliases(node = T.unsafe(nil)); end + def check_with_active_support_aliases(param0 = T.unsafe(nil)); end def on_or(node); end - def two_start_end_with_calls(node = T.unsafe(nil)); end + def two_start_end_with_calls(param0 = T.unsafe(nil)); end private @@ -280,13 +342,15 @@ class RuboCop::Cop::Performance::EndWith < ::RuboCop::Cop::Base def on_match_with_lvasgn(node); end def on_send(node); end - def redundant_regex?(node = T.unsafe(nil)); end + def redundant_regex?(param0 = T.unsafe(nil)); end end RuboCop::Cop::Performance::EndWith::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::EndWith::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::FixedSize < ::RuboCop::Cop::Base - def counter(node = T.unsafe(nil)); end + def counter(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -301,11 +365,13 @@ end RuboCop::Cop::Performance::FixedSize::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::FixedSize::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::FlatMap < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) - def flat_map_candidate?(node = T.unsafe(nil)); end + def flat_map_candidate?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -320,10 +386,12 @@ RuboCop::Cop::Performance::FlatMap::FLATTEN_MULTIPLE_LEVELS = T.let(T.unsafe(nil RuboCop::Cop::Performance::FlatMap::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::FlatMap::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::InefficientHashSearch < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def inefficient_include?(node = T.unsafe(nil)); end + def inefficient_include?(param0 = T.unsafe(nil)); end def on_send(node); end private @@ -336,13 +404,15 @@ class RuboCop::Cop::Performance::InefficientHashSearch < ::RuboCop::Cop::Base def use_long_method; end end +RuboCop::Cop::Performance::InefficientHashSearch::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::IoReadlines < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def readlines_on_class?(node = T.unsafe(nil)); end - def readlines_on_instance?(node = T.unsafe(nil)); end + def readlines_on_class?(param0 = T.unsafe(nil)); end + def readlines_on_instance?(param0 = T.unsafe(nil)); end private @@ -351,36 +421,46 @@ class RuboCop::Cop::Performance::IoReadlines < ::RuboCop::Cop::Base def build_call_args(call_args_node); end def build_good_method(enumerable_call); end def correction_range(enumerable_call, readlines_call); end - def enumerable_method?(node); end def offense_range(enumerable_call, readlines_call); end end -RuboCop::Cop::Performance::IoReadlines::ENUMERABLE_METHODS = T.let(T.unsafe(nil), Array) - RuboCop::Cop::Performance::IoReadlines::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::IoReadlines::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Performance::MethodObjectAsBlock < ::RuboCop::Cop::Base + def method_object_as_argument?(param0 = T.unsafe(nil)); end + def on_block_pass(node); end +end + +RuboCop::Cop::Performance::MethodObjectAsBlock::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Performance::OpenStruct < ::RuboCop::Cop::Base def on_send(node); end - def open_struct(node = T.unsafe(nil)); end + def open_struct(param0 = T.unsafe(nil)); end end RuboCop::Cop::Performance::OpenStruct::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::OpenStruct::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::RangeInclude < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def range_include(node = T.unsafe(nil)); end + def range_include(param0 = T.unsafe(nil)); end end RuboCop::Cop::Performance::RangeInclude::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::RangeInclude::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::RedundantBlockCall < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def blockarg_assigned?(node0, param1); end - def blockarg_calls(node0, param1); end - def blockarg_def(node = T.unsafe(nil)); end + def blockarg_assigned?(param0, param1); end + def blockarg_calls(param0, param1); end + def blockarg_def(param0 = T.unsafe(nil)); end def on_def(node); end private @@ -403,9 +483,9 @@ RuboCop::Cop::Performance::RedundantBlockCall::YIELD = T.let(T.unsafe(nil), Stri class RuboCop::Cop::Performance::RedundantMatch < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def match_call?(node = T.unsafe(nil)); end + def match_call?(param0 = T.unsafe(nil)); end def on_send(node); end - def only_truthiness_matters?(node = T.unsafe(nil)); end + def only_truthiness_matters?(param0 = T.unsafe(nil)); end private @@ -414,12 +494,14 @@ end RuboCop::Cop::Performance::RedundantMatch::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::RedundantMatch::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::RedundantMerge < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def modifier_flow_control?(node = T.unsafe(nil)); end + def modifier_flow_control?(param0 = T.unsafe(nil)); end def on_send(node); end - def redundant_merge_candidate(node = T.unsafe(nil)); end + def redundant_merge_candidate(param0 = T.unsafe(nil)); end private @@ -445,7 +527,7 @@ class RuboCop::Cop::Performance::RedundantMerge::EachWithObjectInspector def initialize(node, receiver); end - def each_with_object_node(node = T.unsafe(nil)); end + def each_with_object_node(param0 = T.unsafe(nil)); end def value_used?; end private @@ -459,6 +541,8 @@ end RuboCop::Cop::Performance::RedundantMerge::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::RedundantMerge::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + RuboCop::Cop::Performance::RedundantMerge::WITH_MODIFIER_CORRECTION = T.let(T.unsafe(nil), String) class RuboCop::Cop::Performance::RedundantSortBlock < ::RuboCop::Cop::Base @@ -480,7 +564,7 @@ class RuboCop::Cop::Performance::RedundantStringChars < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def redundant_chars_call?(node = T.unsafe(nil)); end + def redundant_chars_call?(param0 = T.unsafe(nil)); end private @@ -490,26 +574,25 @@ class RuboCop::Cop::Performance::RedundantStringChars < ::RuboCop::Cop::Base def build_message(method, args); end def correction_range(receiver, node); end def offense_range(receiver, node); end - def replaceable_method?(method_name); end end RuboCop::Cop::Performance::RedundantStringChars::MSG = T.let(T.unsafe(nil), String) -RuboCop::Cop::Performance::RedundantStringChars::REPLACEABLE_METHODS = T.let(T.unsafe(nil), Array) +RuboCop::Cop::Performance::RedundantStringChars::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) class RuboCop::Cop::Performance::RegexpMatch < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def last_matches(node0); end - def match_method?(node = T.unsafe(nil)); end - def match_node?(node = T.unsafe(nil)); end - def match_operator?(node = T.unsafe(nil)); end - def match_threequals?(node = T.unsafe(nil)); end - def match_with_int_arg_method?(node = T.unsafe(nil)); end + def last_matches(param0); end + def match_method?(param0 = T.unsafe(nil)); end + def match_node?(param0 = T.unsafe(nil)); end + def match_operator?(param0 = T.unsafe(nil)); end + def match_threequals?(param0 = T.unsafe(nil)); end + def match_with_int_arg_method?(param0 = T.unsafe(nil)); end def match_with_lvasgn?(node); end def on_case(node); end def on_if(node); end - def search_match_nodes(node0); end + def search_match_nodes(param0); end private @@ -541,7 +624,7 @@ class RuboCop::Cop::Performance::ReverseEach < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def reverse_each?(node = T.unsafe(nil)); end + def reverse_each?(param0 = T.unsafe(nil)); end private @@ -550,6 +633,8 @@ end RuboCop::Cop::Performance::ReverseEach::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::ReverseEach::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + RuboCop::Cop::Performance::ReverseEach::UNDERSCORE = T.let(T.unsafe(nil), String) class RuboCop::Cop::Performance::ReverseFirst < ::RuboCop::Cop::Base @@ -557,7 +642,7 @@ class RuboCop::Cop::Performance::ReverseFirst < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def reverse_first_candidate?(node = T.unsafe(nil)); end + def reverse_first_candidate?(param0 = T.unsafe(nil)); end private @@ -569,17 +654,21 @@ end RuboCop::Cop::Performance::ReverseFirst::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::ReverseFirst::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::Size < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) - def array?(node = T.unsafe(nil)); end - def count?(node = T.unsafe(nil)); end - def hash?(node = T.unsafe(nil)); end + def array?(param0 = T.unsafe(nil)); end + def count?(param0 = T.unsafe(nil)); end + def hash?(param0 = T.unsafe(nil)); end def on_send(node); end end RuboCop::Cop::Performance::Size::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Size::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::SortReverse < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) include(::RuboCop::Cop::SortBlock) @@ -598,7 +687,7 @@ class RuboCop::Cop::Performance::Squeeze < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def squeeze_candidate?(node = T.unsafe(nil)); end + def squeeze_candidate?(param0 = T.unsafe(nil)); end private @@ -609,23 +698,27 @@ RuboCop::Cop::Performance::Squeeze::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Performance::Squeeze::PREFERRED_METHODS = T.let(T.unsafe(nil), Hash) +RuboCop::Cop::Performance::Squeeze::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::StartWith < ::RuboCop::Cop::Base include(::RuboCop::Cop::RegexpMetacharacter) extend(::RuboCop::Cop::AutoCorrector) def on_match_with_lvasgn(node); end def on_send(node); end - def redundant_regex?(node = T.unsafe(nil)); end + def redundant_regex?(param0 = T.unsafe(nil)); end end RuboCop::Cop::Performance::StartWith::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::StartWith::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::StringInclude < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_match_with_lvasgn(node); end def on_send(node); end - def redundant_regex?(node = T.unsafe(nil)); end + def redundant_regex?(param0 = T.unsafe(nil)); end private @@ -634,12 +727,14 @@ end RuboCop::Cop::Performance::StringInclude::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::StringInclude::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::StringReplacement < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def string_replacement?(node = T.unsafe(nil)); end + def string_replacement?(param0 = T.unsafe(nil)); end private @@ -666,39 +761,54 @@ RuboCop::Cop::Performance::StringReplacement::DETERMINISTIC_REGEX = T.let(T.unsa RuboCop::Cop::Performance::StringReplacement::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::StringReplacement::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + RuboCop::Cop::Performance::StringReplacement::TR = T.let(T.unsafe(nil), String) class RuboCop::Cop::Performance::Sum < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) - def acc_plus_elem?(node = T.unsafe(nil), param1, param2); end - def elem_plus_acc?(node = T.unsafe(nil), param1, param2); end + def acc_plus_elem?(param0 = T.unsafe(nil), param1, param2); end + def elem_plus_acc?(param0 = T.unsafe(nil), param1, param2); end def on_block(node); end def on_send(node); end - def sum_candidate?(node = T.unsafe(nil)); end - def sum_with_block_candidate?(node = T.unsafe(nil)); end + def sum_candidate?(param0 = T.unsafe(nil)); end + def sum_map_candidate?(param0 = T.unsafe(nil)); end + def sum_with_block_candidate?(param0 = T.unsafe(nil)); end private + def array_literal?(node); end def autocorrect(corrector, init, range); end + def autocorrect_sum_map(corrector, sum, map, init); end def build_block_bad_method(method, init, var_acc, var_elem, body); end def build_block_message(send, init, var_acc, var_elem, body); end - def build_good_method(init); end + def build_good_method(init, block_pass = T.unsafe(nil)); end def build_method_bad_method(init, method, operation); end - def build_method_message(method, init, operation); end + def build_method_message(node, method, init, operation); end + def build_sum_map_message(method, init); end + def empty_array_literal?(node); end + def handle_sum_candidate(node); end + def handle_sum_map_candidate(node); end + def method_call_with_args_range(node); end def sum_block_range(send, node); end + def sum_map_range(map, sum); end def sum_method_range(node); end end RuboCop::Cop::Performance::Sum::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::Sum::MSG_IF_NO_INIT_VALUE = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Performance::Sum::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::TimesMap < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_block(node); end def on_send(node); end - def times_map_call(node = T.unsafe(nil)); end + def times_map_call(param0 = T.unsafe(nil)); end private @@ -710,23 +820,35 @@ RuboCop::Cop::Performance::TimesMap::MESSAGE = T.let(T.unsafe(nil), String) RuboCop::Cop::Performance::TimesMap::MESSAGE_ONLY_IF = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::TimesMap::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::UnfreezeString < ::RuboCop::Cop::Base - def dup_string?(node = T.unsafe(nil)); end + extend(::RuboCop::Cop::AutoCorrector) + + def dup_string?(param0 = T.unsafe(nil)); end def on_send(node); end - def string_new?(node = T.unsafe(nil)); end + def string_new?(param0 = T.unsafe(nil)); end + + private + + def string_value(node); end end RuboCop::Cop::Performance::UnfreezeString::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::UnfreezeString::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + class RuboCop::Cop::Performance::UriDefaultParser < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) def on_send(node); end - def uri_parser_new?(node = T.unsafe(nil)); end + def uri_parser_new?(param0 = T.unsafe(nil)); end end RuboCop::Cop::Performance::UriDefaultParser::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Performance::UriDefaultParser::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) + module RuboCop::Cop::RegexpMetacharacter private @@ -746,8 +868,8 @@ module RuboCop::Cop::SortBlock include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::AST::NodePattern::Macros) - def replaceable_body?(node = T.unsafe(nil), param1, param2); end - def sort_with_block?(node = T.unsafe(nil)); end + def replaceable_body?(param0 = T.unsafe(nil), param1, param2); end + def sort_with_block?(param0 = T.unsafe(nil)); end private @@ -768,6 +890,9 @@ module RuboCop::Performance::Inject end module RuboCop::Performance::Version + class << self + def document_version; end + end end RuboCop::Performance::Version::STRING = T.let(T.unsafe(nil), String) diff --git a/Library/Homebrew/sorbet/rbi/gems/rubocop@1.2.0.rbi b/Library/Homebrew/sorbet/rbi/gems/rubocop@1.3.1.rbi similarity index 98% rename from Library/Homebrew/sorbet/rbi/gems/rubocop@1.2.0.rbi rename to Library/Homebrew/sorbet/rbi/gems/rubocop@1.3.1.rbi index 3f9abe9dbd..7b89bb575d 100644 --- a/Library/Homebrew/sorbet/rbi/gems/rubocop@1.2.0.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/rubocop@1.3.1.rbi @@ -329,6 +329,7 @@ class RuboCop::ConfigLoader def read_file(absolute_path); end def resolver; end def yaml_safe_load(yaml_code, filename); end + def yaml_safe_load!(yaml_code, filename); end end end @@ -674,11 +675,11 @@ RuboCop::Cop::Base::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Set) module RuboCop::Cop::Bundler end -class RuboCop::Cop::Bundler::DuplicatedGem < ::RuboCop::Cop::Cop +class RuboCop::Cop::Bundler::DuplicatedGem < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) def gem_declarations(param0); end - def investigate(processed_source); end + def on_new_investigation; end private @@ -690,7 +691,7 @@ end RuboCop::Cop::Bundler::DuplicatedGem::MSG = T.let(T.unsafe(nil), String) -class RuboCop::Cop::Bundler::GemComment < ::RuboCop::Cop::Cop +class RuboCop::Cop::Bundler::GemComment < ::RuboCop::Cop::Base include(::RuboCop::Cop::DefNode) def gem_declaration?(param0 = T.unsafe(nil)); end @@ -1298,12 +1299,12 @@ RuboCop::Cop::FrozenStringLiteral::FROZEN_STRING_LITERAL_TYPES = T.let(T.unsafe( module RuboCop::Cop::Gemspec end -class RuboCop::Cop::Gemspec::DuplicatedAssignment < ::RuboCop::Cop::Cop +class RuboCop::Cop::Gemspec::DuplicatedAssignment < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) def assignment_method_declarations(param0); end def gem_specification(param0); end - def investigate(processed_source); end + def on_new_investigation; end private @@ -1331,11 +1332,11 @@ end RuboCop::Cop::Gemspec::OrderedDependencies::MSG = T.let(T.unsafe(nil), String) -class RuboCop::Cop::Gemspec::RequiredRubyVersion < ::RuboCop::Cop::Cop +class RuboCop::Cop::Gemspec::RequiredRubyVersion < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) def defined_ruby_version(param0 = T.unsafe(nil)); end - def investigate(processed_source); end + def on_new_investigation; end def required_ruby_version(param0); end private @@ -1348,7 +1349,7 @@ RuboCop::Cop::Gemspec::RequiredRubyVersion::MISSING_MSG = T.let(T.unsafe(nil), S RuboCop::Cop::Gemspec::RequiredRubyVersion::NOT_EQUAL_MSG = T.let(T.unsafe(nil), String) -class RuboCop::Cop::Gemspec::RubyVersionGlobalsUsage < ::RuboCop::Cop::Cop +class RuboCop::Cop::Gemspec::RubyVersionGlobalsUsage < ::RuboCop::Cop::Base def gem_specification?(param0); end def on_const(node); end def ruby_version?(param0 = T.unsafe(nil)); end @@ -1372,7 +1373,6 @@ class RuboCop::Cop::Generator private def badge; end - def bump_minor_version; end def generate(template); end def generated_source; end def generated_spec; end @@ -1387,7 +1387,7 @@ end RuboCop::Cop::Generator::CONFIGURATION_ADDED_MESSAGE = T.let(T.unsafe(nil), String) class RuboCop::Cop::Generator::ConfigurationInjector - def initialize(configuration_file_path:, badge:, version_added:); end + def initialize(configuration_file_path:, badge:, version_added: T.unsafe(nil)); end def inject; end @@ -1793,6 +1793,7 @@ class RuboCop::Cop::Layout::ClassStructure < ::RuboCop::Cop::Base include(::RuboCop::Cop::VisibilityHelp) extend(::RuboCop::Cop::AutoCorrector) + def dynamic_constant?(param0 = T.unsafe(nil)); end def on_class(class_node); end private @@ -1809,6 +1810,7 @@ class RuboCop::Cop::Layout::ClassStructure < ::RuboCop::Cop::Base def find_heredoc(node); end def humanize_node(node); end def ignore?(classification); end + def ignore_for_autocorrect?(node, sibling); end def source_range_with_comment(node); end def start_line_position(node); end def walk_over_nested_class_definition(class_node); end @@ -2756,6 +2758,7 @@ class RuboCop::Cop::Layout::LineLength < ::RuboCop::Cop::Cop include(::RuboCop::Cop::LineLengthHelp) def autocorrect(range); end + def correctable?; end def investigate(processed_source); end def investigate_post_walk(processed_source); end def on_array(node); end @@ -2769,6 +2772,8 @@ class RuboCop::Cop::Layout::LineLength < ::RuboCop::Cop::Cop def allow_heredoc?; end def allowed_heredoc; end def breakable_block_range(block_node); end + def breakable_range; end + def breakable_range=(_arg0); end def breakable_range_after_semicolon(semicolon_token); end def breakable_range_by_line_index; end def check_directive_line(line, line_index); end @@ -3770,11 +3775,17 @@ end RuboCop::Cop::Lint::CircularArgumentReference::MSG = T.let(T.unsafe(nil), String) class RuboCop::Cop::Lint::ConstantDefinitionInBlock < ::RuboCop::Cop::Base + include(::RuboCop::Cop::AllowedMethods) + def constant_assigned_in_block?(param0 = T.unsafe(nil)); end def module_defined_in_block?(param0 = T.unsafe(nil)); end def on_casgn(node); end def on_class(node); end def on_module(node); end + + private + + def method_name(node); end end RuboCop::Cop::Lint::ConstantDefinitionInBlock::MSG = T.let(T.unsafe(nil), String) @@ -3793,14 +3804,12 @@ end RuboCop::Cop::Lint::ConstantResolution::MSG = T.let(T.unsafe(nil), String) class RuboCop::Cop::Lint::Debugger < ::RuboCop::Cop::Base - def binding_irb_call?(param0 = T.unsafe(nil)); end - def debugger_call?(param0 = T.unsafe(nil)); end - def kernel?(param0 = T.unsafe(nil)); end def on_send(node); end private - def binding_irb?(node); end + def debugger_method?(name); end + def debugger_receiver?(node); end def message(node); end end @@ -3874,12 +3883,23 @@ end RuboCop::Cop::Lint::DisjunctiveAssignmentInConstructor::MSG = T.let(T.unsafe(nil), String) -class RuboCop::Cop::Lint::DuplicateCaseCondition < ::RuboCop::Cop::Base - def on_case(case_node); end +class RuboCop::Cop::Lint::DuplicateBranch < ::RuboCop::Cop::Base + include(::RuboCop::Cop::RescueNode) + + def on_branching_statement(node); end + def on_case(node); end + def on_if(node); end + def on_rescue(node); end private - def repeated_condition?(previous, condition); end + def offense_range(duplicate_branch); end +end + +RuboCop::Cop::Lint::DuplicateBranch::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Lint::DuplicateCaseCondition < ::RuboCop::Cop::Base + def on_case(case_node); end end RuboCop::Cop::Lint::DuplicateCaseCondition::MSG = T.let(T.unsafe(nil), String) @@ -3994,11 +4014,25 @@ class RuboCop::Cop::Lint::EmptyBlock < ::RuboCop::Cop::Base private def allow_comment?(node); end + def allow_empty_lambdas?; end def comment_disables_cop?(comment); end end RuboCop::Cop::Lint::EmptyBlock::MSG = T.let(T.unsafe(nil), String) +class RuboCop::Cop::Lint::EmptyClass < ::RuboCop::Cop::Base + def on_class(node); end + def on_sclass(node); end + + private + + def body_or_allowed_comment_lines?(node); end +end + +RuboCop::Cop::Lint::EmptyClass::CLASS_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Lint::EmptyClass::METACLASS_MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Lint::EmptyConditionalBody < ::RuboCop::Cop::Base def on_if(node); end end @@ -4320,8 +4354,11 @@ class RuboCop::Cop::Lint::LiteralInInterpolation < ::RuboCop::Cop::Base def autocorrected_value_for_array(node); end def autocorrected_value_for_string(node); end def autocorrected_value_for_symbol(node); end + def ends_heredoc_line?(node); end def in_array_percent_literal?(node); end + def offending?(node); end def prints_as_self?(node); end + def space_literal?(node); end def special_keyword?(node); end end @@ -4690,8 +4727,10 @@ class RuboCop::Cop::Lint::RedundantCopEnableDirective < ::RuboCop::Cop::Base def comment_start(comment); end def cop_name_indention(comment, name); end def range_of_offense(comment, name); end - def range_to_remove(begin_pos, end_pos, comma_pos, comment); end + def range_to_remove(begin_pos, end_pos, comment); end def range_with_comma(comment, name); end + def range_with_comma_after(comment, start, begin_pos, end_pos); end + def range_with_comma_before(start, begin_pos, end_pos); end def register_offense(comment, cop_names); end end @@ -6100,6 +6139,8 @@ class RuboCop::Cop::Naming::VariableNumber < ::RuboCop::Cop::Base private + def allowed_identifier?(name); end + def allowed_identifiers; end def message(style); end end @@ -6541,6 +6582,7 @@ module RuboCop::Cop::StatementModifier private + def code_after(node); end def comment_disables_cop?(comment); end def first_line_comment(node); end def length_in_modifier_form(node); end @@ -7425,9 +7467,20 @@ class RuboCop::Cop::Style::DocumentDynamicEvalDefinition < ::RuboCop::Cop::Base private - def comment_docs?(node); end + def comment_block_docs?(arg_node); end + def comment_regexp(arg_node); end + def heredoc_comment_blocks(heredoc_body); end + def inline_comment_docs?(node); end + def interpolated?(arg_node); end + def merge_adjacent_comments(line, index, hash); end + def preceding_comment_blocks(node); end + def source_to_regexp(source); end end +RuboCop::Cop::Style::DocumentDynamicEvalDefinition::BLOCK_COMMENT_REGEXP = T.let(T.unsafe(nil), Regexp) + +RuboCop::Cop::Style::DocumentDynamicEvalDefinition::COMMENT_REGEXP = T.let(T.unsafe(nil), Regexp) + RuboCop::Cop::Style::DocumentDynamicEvalDefinition::MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Style::DocumentDynamicEvalDefinition::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) @@ -8091,12 +8144,18 @@ class RuboCop::Cop::Style::IfCorrector end class RuboCop::Cop::Style::IfInsideElse < ::RuboCop::Cop::Base + include(::RuboCop::Cop::RangeHelp) + extend(::RuboCop::Cop::AutoCorrector) + def on_if(node); end private def allow_if_modifier?; end def allow_if_modifier_in_else_branch?(else_branch); end + def autocorrect(corrector, node); end + def correct_to_elsif_from_if_inside_else_form(corrector, node, condition); end + def correct_to_elsif_from_modifier_form(corrector, node); end end RuboCop::Cop::Style::IfInsideElse::MSG = T.let(T.unsafe(nil), String) @@ -8736,8 +8795,10 @@ class RuboCop::Cop::Style::NegatedIf < ::RuboCop::Cop::Base end class RuboCop::Cop::Style::NegatedIfElseCondition < ::RuboCop::Cop::Base + include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) + def double_negation?(param0 = T.unsafe(nil)); end def on_if(node); end def on_new_investigation; end @@ -8896,6 +8957,16 @@ RuboCop::Cop::Style::NilComparison::PREDICATE_MSG = T.let(T.unsafe(nil), String) RuboCop::Cop::Style::NilComparison::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) +class RuboCop::Cop::Style::NilLambda < ::RuboCop::Cop::Base + include(::RuboCop::Cop::RangeHelp) + extend(::RuboCop::Cop::AutoCorrector) + + def nil_return?(param0 = T.unsafe(nil)); end + def on_block(node); end +end + +RuboCop::Cop::Style::NilLambda::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Style::NonNilCheck < ::RuboCop::Cop::Base extend(::RuboCop::Cop::AutoCorrector) @@ -10129,6 +10200,21 @@ RuboCop::Cop::Style::StabbyLambdaParentheses::MSG_NO_REQUIRE = T.let(T.unsafe(ni RuboCop::Cop::Style::StabbyLambdaParentheses::MSG_REQUIRE = T.let(T.unsafe(nil), String) +class RuboCop::Cop::Style::StaticClass < ::RuboCop::Cop::Base + include(::RuboCop::Cop::VisibilityHelp) + + def on_class(class_node); end + + private + + def class_convertible_to_module?(class_node); end + def class_elements(class_node); end + def extend_call?(node); end + def sclass_convertible_to_module?(node); end +end + +RuboCop::Cop::Style::StaticClass::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Style::StderrPuts < ::RuboCop::Cop::Base include(::RuboCop::Cop::RangeHelp) extend(::RuboCop::Cop::AutoCorrector) @@ -11664,9 +11750,9 @@ RuboCop::Formatter::PacmanFormatter::FALLBACK_TERMINAL_WIDTH = T.let(T.unsafe(ni RuboCop::Formatter::PacmanFormatter::GHOST = T.let(T.unsafe(nil), String) -RuboCop::Formatter::PacmanFormatter::PACDOT = T.let(T.unsafe(nil), Rainbow::NullPresenter) +RuboCop::Formatter::PacmanFormatter::PACDOT = T.let(T.unsafe(nil), Rainbow::Presenter) -RuboCop::Formatter::PacmanFormatter::PACMAN = T.let(T.unsafe(nil), Rainbow::NullPresenter) +RuboCop::Formatter::PacmanFormatter::PACMAN = T.let(T.unsafe(nil), Rainbow::Presenter) class RuboCop::Formatter::ProgressFormatter < ::RuboCop::Formatter::ClangStyleFormatter include(::RuboCop::Formatter::TextUtil) @@ -12130,6 +12216,25 @@ class RuboCop::TargetRuby::Default < ::RuboCop::TargetRuby::Source def find_version; end end +class RuboCop::TargetRuby::GemspecFile < ::RuboCop::TargetRuby::Source + extend(::RuboCop::AST::NodePattern::Macros) + + def gem_requirement?(param0 = T.unsafe(nil)); end + def name; end + def required_ruby_version(param0); end + + private + + def find_version; end + def gemspec_filename; end + def gemspec_filepath; end + def version_from_array(array); end + def version_from_gemspec_file(file); end + def version_from_str(str); end +end + +RuboCop::TargetRuby::GemspecFile::GEMSPEC_EXTENSION = T.let(T.unsafe(nil), String) + class RuboCop::TargetRuby::RuboCopConfig < ::RuboCop::TargetRuby::Source def name; end diff --git a/Library/Homebrew/sorbet/rbi/gems/ruby-macho@2.2.0.rbi b/Library/Homebrew/sorbet/rbi/gems/ruby-macho@2.5.0.rbi similarity index 100% rename from Library/Homebrew/sorbet/rbi/gems/ruby-macho@2.2.0.rbi rename to Library/Homebrew/sorbet/rbi/gems/ruby-macho@2.5.0.rbi diff --git a/Library/Homebrew/sorbet/rbi/gems/tzinfo@1.2.7.rbi b/Library/Homebrew/sorbet/rbi/gems/tzinfo@1.2.7.rbi deleted file mode 100644 index fca7e051ee..0000000000 --- a/Library/Homebrew/sorbet/rbi/gems/tzinfo@1.2.7.rbi +++ /dev/null @@ -1,7 +0,0 @@ -# DO NOT EDIT MANUALLY -# This is an autogenerated file for types exported from the `tzinfo` gem. -# Please instead update this file by running `tapioca generate --exclude json`. - -# typed: true - - diff --git a/Library/Homebrew/sorbet/rbi/gems/tzinfo@1.2.8.rbi b/Library/Homebrew/sorbet/rbi/gems/tzinfo@1.2.8.rbi new file mode 100644 index 0000000000..45e4a0cda5 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/tzinfo@1.2.8.rbi @@ -0,0 +1,8 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `tzinfo` gem. +# Please instead update this file by running `tapioca sync`. + +# typed: true + +# THIS IS AN EMPTY RBI FILE. +# see https://github.com/Shopify/tapioca/blob/master/README.md#manual-gem-requires diff --git a/Library/Homebrew/sorbet/rbi/gems/zeitwerk@2.4.0.rbi b/Library/Homebrew/sorbet/rbi/gems/zeitwerk@2.4.0.rbi deleted file mode 100644 index 78c0137b3e..0000000000 --- a/Library/Homebrew/sorbet/rbi/gems/zeitwerk@2.4.0.rbi +++ /dev/null @@ -1,7 +0,0 @@ -# DO NOT EDIT MANUALLY -# This is an autogenerated file for types exported from the `zeitwerk` gem. -# Please instead update this file by running `tapioca generate --exclude json`. - -# typed: true - - diff --git a/Library/Homebrew/sorbet/rbi/gems/zeitwerk@2.4.1.rbi b/Library/Homebrew/sorbet/rbi/gems/zeitwerk@2.4.1.rbi new file mode 100644 index 0000000000..1843429730 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/zeitwerk@2.4.1.rbi @@ -0,0 +1,8 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `zeitwerk` gem. +# Please instead update this file by running `tapioca sync`. + +# typed: true + +# THIS IS AN EMPTY RBI FILE. +# see https://github.com/Shopify/tapioca/blob/master/README.md#manual-gem-requires diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index 24874c0019..f3328d7d4b 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -7,6 +7,11 @@ class AbstractDownloadStrategy include ::FileUtils::StreamUtils_ end +class AbstractDownloadStrategy + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module ActiveSupport def parse_json_times(); end @@ -2980,10 +2985,6 @@ end BasicObject::BasicObject = BasicObject -class BasicSocket - def read_nonblock(len, str=T.unsafe(nil), exception: T.unsafe(nil)); end -end - class Benchmark::Job def initialize(width); end end @@ -3019,29 +3020,22 @@ class Binding def irb(); end end -class Bottle - def cached_download(*args, &block); end - - def clear_cache(*args, &block); end - - def fetch(*args, &block); end - - def url(*args, &block); end - - def verify_download_integrity(*args, &block); end +class Bintray + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end class BottleSpecification - def cellar(val=T.unsafe(nil)); end - - def prefix(val=T.unsafe(nil)); end - - def rebuild(val=T.unsafe(nil)); end - - def sha256(val); end + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end -class BottleSpecification +module BuildEnvironment::DSL + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class BuildEnvironment extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks end @@ -5480,16 +5474,24 @@ end module CGI::HtmlExtension end +class Cask::AbstractCaskErrorWithToken + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Cask::Artifact::AbstractArtifact + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Cask::Audit - def appcast?(); end + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def new_cask?(); end - - def online?(); end - - def strict?(); end - - def token_conflicts?(); end +module Cask::Cache + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end class Cask::Cask @@ -5584,6 +5586,45 @@ class Cask::Cask def zap(&block); end end +class Cask::Cask + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Cask::CaskLoader::FromURILoader + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Cask::CaskLoader::NullLoader + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Cask::CaskQuarantineError + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Cask::CaskUnspecifiedError + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module Cask::Caskroom + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Cask::Cmd::AbstractCommand + include ::Homebrew::Search::Extension +end + +class Cask::Cmd::AbstractCommand + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Cask::Config def appdir(); end @@ -5717,8 +5758,6 @@ class Cask::DSL::Caveats def discontinued(*args); end - def discontinued?(); end - def files_in_usr_local(*args); end def free_license(*args); end @@ -5772,24 +5811,34 @@ class Cask::DSL::Version def underscores_to_hyphens(); end end -class Cask::Installer - def binaries?(); end +module Cask::Denylist + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def force?(); end +class Cask::MultipleCaskErrors + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def installed_as_dependency?(); end +class Cask::Pkg + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def quarantine?(); end +module Cask::Quarantine + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def reinstall?(); end +module Cask::Staged + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def require_sha?(); end - - def skip_cask_deps?(); end - - def upgrade?(); end - - def verbose?(); end +module Cask::Utils + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end class Caveats @@ -6233,6 +6282,11 @@ module CopHelper extend ::RSpec::Its end +class CxxStdlib + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class DRb::DRbArray def _dump(lv); end end @@ -6703,9 +6757,12 @@ class Debrew::Menu::Entry def self.members(); end end -module Debrew - def self.active?(); end +class Debrew::Menu + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end +module Debrew def self.lock(); end def self.locked?(); end @@ -6721,10 +6778,34 @@ class Delegator include ::ActiveSupport::Tryable end +class Dependencies + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module DependenciesHelpers include ::DependenciesHelpers::Compat end +class Dependency + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class DependencyCollector + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class DeprecatedOption + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class DevelopmentTools + extend ::T::Private::Methods::SingletonMethodHooks +end + class Dir def children(); end @@ -6735,6 +6816,11 @@ class Dir def self.exists?(_); end end +module DiskUsageExtension + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Docile VERSION = ::T.let(nil, ::T.untyped) end @@ -6923,6 +7009,11 @@ module ERB::Util def self.unwrapped_html_escape(s); end end +class EmbeddedPatch + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Encoding def _dump(*_); end end @@ -6979,37 +7070,86 @@ class Enumerator::Generator def initialize(*_); end end -Errno::EAUTH = Errno::NOERROR +module EnvVar + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end -Errno::EBADARCH = Errno::NOERROR +class Errno::EAUTH + Errno = ::T.let(nil, ::T.untyped) +end -Errno::EBADEXEC = Errno::NOERROR +class Errno::EAUTH +end -Errno::EBADMACHO = Errno::NOERROR +class Errno::EBADARCH + Errno = ::T.let(nil, ::T.untyped) +end -Errno::EBADRPC = Errno::NOERROR +class Errno::EBADARCH +end -Errno::ECAPMODE = Errno::NOERROR +class Errno::EBADEXEC + Errno = ::T.let(nil, ::T.untyped) +end -Errno::EDEADLOCK = Errno::EDEADLK +class Errno::EBADEXEC +end -Errno::EDEVERR = Errno::NOERROR +class Errno::EBADMACHO + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::EBADMACHO +end + +class Errno::EBADRPC + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::EBADRPC +end + +Errno::EDEADLOCK = Errno::NOERROR + +class Errno::EDEVERR + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::EDEVERR +end Errno::EDOOFUS = Errno::NOERROR -Errno::EFTYPE = Errno::NOERROR +class Errno::EFTYPE + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::EFTYPE +end Errno::EIPSEC = Errno::NOERROR -Errno::ELAST = Errno::NOERROR +class Errno::ENEEDAUTH + Errno = ::T.let(nil, ::T.untyped) +end -Errno::ENEEDAUTH = Errno::NOERROR +class Errno::ENEEDAUTH +end -Errno::ENOATTR = Errno::NOERROR +class Errno::ENOATTR + Errno = ::T.let(nil, ::T.untyped) +end -Errno::ENOPOLICY = Errno::NOERROR +class Errno::ENOATTR +end -Errno::ENOTCAPABLE = Errno::NOERROR +class Errno::ENOPOLICY + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::ENOPOLICY +end class Errno::ENOTSUP Errno = ::T.let(nil, ::T.untyped) @@ -7018,21 +7158,61 @@ end class Errno::ENOTSUP end -Errno::EPROCLIM = Errno::NOERROR +class Errno::EPROCLIM + Errno = ::T.let(nil, ::T.untyped) +end -Errno::EPROCUNAVAIL = Errno::NOERROR +class Errno::EPROCLIM +end -Errno::EPROGMISMATCH = Errno::NOERROR +class Errno::EPROCUNAVAIL + Errno = ::T.let(nil, ::T.untyped) +end -Errno::EPROGUNAVAIL = Errno::NOERROR +class Errno::EPROCUNAVAIL +end -Errno::EPWROFF = Errno::NOERROR +class Errno::EPROGMISMATCH + Errno = ::T.let(nil, ::T.untyped) +end -Errno::EQFULL = Errno::NOERROR +class Errno::EPROGMISMATCH +end -Errno::ERPCMISMATCH = Errno::NOERROR +class Errno::EPROGUNAVAIL + Errno = ::T.let(nil, ::T.untyped) +end -Errno::ESHLIBVERS = Errno::NOERROR +class Errno::EPROGUNAVAIL +end + +class Errno::EPWROFF + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::EPWROFF +end + +class Errno::EQFULL + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::EQFULL +end + +class Errno::ERPCMISMATCH + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::ERPCMISMATCH +end + +class Errno::ESHLIBVERS + Errno = ::T.let(nil, ::T.untyped) +end + +class Errno::ESHLIBVERS +end class Etc::Group def gid(); end @@ -7062,8 +7242,16 @@ class Etc::Group end class Etc::Passwd + def change(); end + + def change=(_); end + def dir=(_); end + def expire(); end + + def expire=(_); end + def gecos(); end def gecos=(_); end @@ -7076,6 +7264,10 @@ class Etc::Passwd def shell=(_); end + def uclass(); end + + def uclass=(_); end + def uid=(_); end end @@ -7151,6 +7343,11 @@ class ExternalPatch def verify_download_integrity(*args, &block); end end +class ExternalPatch + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class FalseClass include ::JSON::Ext::Generator::GeneratorMethods::FalseClass end @@ -7163,18 +7360,6 @@ class Fiber def self.current(); end end -module Fiddle - NULL = ::T.let(nil, ::T.untyped) - RTLD_GLOBAL = ::T.let(nil, ::T.untyped) - RTLD_LAZY = ::T.let(nil, ::T.untyped) - RTLD_NOW = ::T.let(nil, ::T.untyped) - WINDOWS = ::T.let(nil, ::T.untyped) -end - -class Fiddle::Function - STDCALL = ::T.let(nil, ::T.untyped) -end - class File def self.atomic_write(file_name, temp_dir=T.unsafe(nil)); end @@ -7229,101 +7414,7 @@ module FileUtils end class Formula - include ::FileUtils::StreamUtils_ include ::Formula::Compat - def bottle_defined?(*args, &block); end - - def bottle_disable_reason(*args, &block); end - - def bottle_disabled?(*args, &block); end - - def bottle_specification(*args, &block); end - - def bottle_unneeded?(*args, &block); end - - def bottled?(*args, &block); end - - def cached_download(*args, &block); end - - def clear_cache(*args, &block); end - - def compiler_failures(*args, &block); end - - def conflicts(*args, &block); end - - def deprecated?(*args, &block); end - - def deprecated_flags(*args, &block); end - - def deprecated_options(*args, &block); end - - def deprecation_reason(*args, &block); end - - def deps(*args, &block); end - - def desc(*args, &block); end - - def disable_reason(*args, &block); end - - def disabled?(*args, &block); end - - def downloader(*args, &block); end - - def env(*args, &block); end - - def homepage(*args, &block); end - - def keg_only_reason(*args, &block); end - - def license(*args, &block); end - - def livecheck(*args, &block); end - - def livecheckable?(*args, &block); end - - def option_defined?(*args, &block); end - - def options(*args, &block); end - - def patchlist(*args, &block); end - - def pin(*args, &block); end - - def pinnable?(*args, &block); end - - def pinned?(*args, &block); end - - def pinned_version(*args, &block); end - - def plist_manual(*args, &block); end - - def plist_startup(*args, &block); end - - def pour_bottle_check_unsatisfied_reason(*args, &block); end - - def requirements(*args, &block); end - - def resource(*args, &block); end - - def resources(*args, &block); end - - def unpin(*args, &block); end - - def uses_from_macos_elements(*args, &block); end - - def version(*args, &block); end -end - -class Formula - def self.desc(val=T.unsafe(nil)); end - - def self.homepage(val=T.unsafe(nil)); end - - def self.revision(val=T.unsafe(nil)); end - - def self.sha256(val); end - - def self.version_scheme(val=T.unsafe(nil)); end end module FormulaCellarChecks @@ -7337,32 +7428,14 @@ class FormulaConflict def self.members(); end end -class FormulaInstaller - def debug=(debug); end +class Formulary::FromUrlLoader + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end - def force=(force); end - - def force_bottle=(force_bottle); end - - def git=(git); end - - def hold_locks?(); end - - def ignore_deps=(ignore_deps); end - - def interactive=(interactive); end - - def keep_tmp=(keep_tmp); end - - def only_deps=(only_deps); end - - def quiet=(quiet); end - - def show_header=(show_header); end - - def show_summary_heading=(show_summary_heading); end - - def verbose=(verbose); end +module Formulary + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end module Forwardable @@ -7993,11 +8066,27 @@ end module GetText end +class GitHub::Actions::Annotation + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module GitHub::Actions + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module GitHub + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class HTTP::Cookie def self.parse(set_cookie, origin, options=T.unsafe(nil), &block); end end class Hardware::CPU + extend ::T::Private::Methods::SingletonMethodHooks def self.lm?(); end end @@ -8058,22 +8147,38 @@ class Hash def self.try_convert(_); end end +class HeadVersion + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Homebrew MAX_PORT = ::T.let(nil, ::T.untyped) MIN_PORT = ::T.let(nil, ::T.untyped) end +class Homebrew::CLI::Args + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Homebrew::CLI::NamedArgs + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Homebrew::CLI::Parser include ::Homebrew::CLI::Parser::Compat end -class Homebrew::Cleanup - def dry_run?(); end - - def scrub?(); end +class Homebrew::CLI::Parser + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end module Homebrew::EnvConfig + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks def self.all_proxy(); end def self.arch(); end @@ -8199,13 +8304,33 @@ module Homebrew::EnvConfig def self.verbose_using_dots?(); end end +class Homebrew::FormulaCreator + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Homebrew::MissingFormula extend ::T::Private::Methods::SingletonMethodHooks end +module Homebrew::Search + include ::Homebrew::Search::Extension +end + +class Homebrew::Style::LineLocation + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Homebrew::TapAuditor + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Homebrew extend ::FileUtils::StreamUtils_ - extend ::DependenciesHelpers::Compat + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks extend ::Homebrew::Compat def self.default_prefix?(prefix=T.unsafe(nil)); end end @@ -10309,6 +10434,8 @@ class JSON::Ext::Parser end class JavaRequirement::CaskSuggestion + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks def self.[](*_); end def self.members(); end @@ -10344,12 +10471,27 @@ class Keg def to_s(*args, &block); end end +class Keg::ConflictError + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Keg::DirectoryNotWritableError + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Keg::Relocation def self.[](*_); end def self.members(); end end +class Keg + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class KegOnlyReason extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks @@ -10370,11 +10512,13 @@ module Kernel end module Kernel + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks def self.at_exit(); end - def self.load(*_); end + def self.gem(dep, *reqs); end - def self.method_added(name); end + def self.load(*_); end def self.require(path); end end @@ -10383,10 +10527,25 @@ module Language::Haskell::Cabal include ::Language::Haskell::Cabal::Compat end +module Language::Node + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module Language::Python::Virtualenv + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class LoadError def is_missing?(location); end end +class Locale + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Logger SEV_LABEL = ::T.let(nil, ::T.untyped) end @@ -10428,6 +10587,12 @@ end class MachO::CPUTypeError end +class MachO::CodeSigningError +end + +class MachO::CodeSigningError +end + class MachO::DylibIdMissingError def initialize(); end end @@ -11547,7 +11712,7 @@ class MachO::MachOView end class MachO::MagicError - def initialize(num); end + def initialize(magic); end end class MachO::MagicError @@ -11560,7 +11725,6 @@ class MachO::ModificationError end class MachO::NotAMachOError - def initialize(error); end end class MachO::NotAMachOError @@ -11724,6 +11888,8 @@ module MachO::Utils end module MachO + def self.codesign!(filename); end + def self.open(filename); end end @@ -11741,6 +11907,11 @@ module Marshal extend ::ActiveSupport::MarshalWithAutoloading end +class Messages + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Method include ::MethodSource::SourceLocation::MethodExtensions include ::MethodSource::MethodExtensions @@ -11835,6 +12006,11 @@ module MethodSource def self.valid_expression?(str); end end +class Migrator + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + MiniTest = Minitest module Minitest @@ -12539,6 +12715,11 @@ class Mktemp include ::FileUtils::StreamUtils_ end +class Mktemp + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class MockExpectationError end @@ -13139,6 +13320,8 @@ class Net::HTTP::Persistent def self.detect_idle_timeout(uri, max=T.unsafe(nil)); end end +Net::HTTP::ProxyMod = Net::HTTP::ProxyDelta + class Net::HTTPAlreadyReported HAS_BODY = ::T.let(nil, ::T.untyped) end @@ -13146,8 +13329,6 @@ end class Net::HTTPAlreadyReported end -Net::HTTPClientError::EXCEPTION_TYPE = Net::HTTPServerException - Net::HTTPClientErrorCode = Net::HTTPClientError class Net::HTTPEarlyHints @@ -13209,8 +13390,6 @@ end class Net::HTTPRangeNotSatisfiable end -Net::HTTPRedirection::EXCEPTION_TYPE = Net::HTTPRetriableError - Net::HTTPRedirectionCode = Net::HTTPRedirection Net::HTTPRequestURITooLarge = Net::HTTPURITooLong @@ -13219,8 +13398,6 @@ Net::HTTPResponceReceiver = Net::HTTPResponse Net::HTTPRetriableCode = Net::HTTPRedirection -Net::HTTPServerError::EXCEPTION_TYPE = Net::HTTPFatalError - Net::HTTPServerErrorCode = Net::HTTPServerError Net::HTTPSession = Net::HTTP @@ -13342,6 +13519,51 @@ class Numeric TERABYTE = ::T.let(nil, ::T.untyped) end +module OS::Linux::Glibc + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module OS::Linux::Kernel + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module OS::Linux + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module OS::Mac::CLT + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class OS::Mac::CLTSDKLocator + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module OS::Mac::XQuartz + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module OS::Mac::Xcode + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class OS::Mac::XcodeSDKLocator + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module OS::Mac + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Object include ::ActiveSupport::Dependencies::Loadable include ::ActiveSupport::Tryable @@ -13376,18 +13598,14 @@ class Object def to_query(key); end def to_yaml(options=T.unsafe(nil)); end - APPLY_A = ::T.let(nil, ::T.untyped) - APPLY_B = ::T.let(nil, ::T.untyped) - APPLY_C = ::T.let(nil, ::T.untyped) + APPLE_GEM_HOME = ::T.let(nil, ::T.untyped) ARGF = ::T.let(nil, ::T.untyped) ARGV = ::T.let(nil, ::T.untyped) - BOTTLE_ERB = ::T.let(nil, ::T.untyped) BUG_REPORTS_URL = ::T.let(nil, ::T.untyped) COMMAND_DESC_WIDTH = ::T.let(nil, ::T.untyped) CROSS_COMPILING = ::T.let(nil, ::T.untyped) DEPRECATED_OFFICIAL_TAPS = ::T.let(nil, ::T.untyped) ENV = ::T.let(nil, ::T.untyped) - HEAD_URL = ::T.let(nil, ::T.untyped) HOMEBREW_BOTTLE_DEFAULT_DOMAIN = ::T.let(nil, ::T.untyped) HOMEBREW_BREW_DEFAULT_GIT_REMOTE = ::T.let(nil, ::T.untyped) HOMEBREW_BREW_FILE = ::T.let(nil, ::T.untyped) @@ -13429,19 +13647,13 @@ class Object HOMEBREW_USER_AGENT_RUBY = ::T.let(nil, ::T.untyped) HOMEBREW_VERSION = ::T.let(nil, ::T.untyped) HOMEBREW_WWW = ::T.let(nil, ::T.untyped) - HOMEPAGE_URL = ::T.let(nil, ::T.untyped) - MAXIMUM_STRING_MATCHES = ::T.let(nil, ::T.untyped) OFFICIAL_CASK_TAPS = ::T.let(nil, ::T.untyped) OFFICIAL_CMD_TAPS = ::T.let(nil, ::T.untyped) OPTION_DESC_WIDTH = ::T.let(nil, ::T.untyped) ORIGINAL_PATHS = ::T.let(nil, ::T.untyped) OS_VERSION = ::T.let(nil, ::T.untyped) - PATCH_A_CONTENTS = ::T.let(nil, ::T.untyped) PATCH_A_SHA256 = ::T.let(nil, ::T.untyped) - PATCH_B_CONTENTS = ::T.let(nil, ::T.untyped) PATCH_B_SHA256 = ::T.let(nil, ::T.untyped) - PATCH_URL_A = ::T.let(nil, ::T.untyped) - PATCH_URL_B = ::T.let(nil, ::T.untyped) REQUIRED_RUBY_X = ::T.let(nil, ::T.untyped) REQUIRED_RUBY_Y = ::T.let(nil, ::T.untyped) RUBY_BIN = ::T.let(nil, ::T.untyped) @@ -13449,6 +13661,8 @@ class Object RUBY_DESCRIPTION = ::T.let(nil, ::T.untyped) RUBY_ENGINE = ::T.let(nil, ::T.untyped) RUBY_ENGINE_VERSION = ::T.let(nil, ::T.untyped) + RUBY_FRAMEWORK = ::T.let(nil, ::T.untyped) + RUBY_FRAMEWORK_VERSION = ::T.let(nil, ::T.untyped) RUBY_PATCHLEVEL = ::T.let(nil, ::T.untyped) RUBY_PATH = ::T.let(nil, ::T.untyped) RUBY_PLATFORM = ::T.let(nil, ::T.untyped) @@ -13457,15 +13671,11 @@ class Object RUBY_VERSION = ::T.let(nil, ::T.untyped) RUBY_X = ::T.let(nil, ::T.untyped) RUBY_Y = ::T.let(nil, ::T.untyped) - STABLE_URL = ::T.let(nil, ::T.untyped) STDERR = ::T.let(nil, ::T.untyped) STDIN = ::T.let(nil, ::T.untyped) STDOUT = ::T.let(nil, ::T.untyped) TESTBALL_PATCHES_SHA256 = ::T.let(nil, ::T.untyped) - TESTBALL_PATCHES_URL = ::T.let(nil, ::T.untyped) TESTBALL_SHA256 = ::T.let(nil, ::T.untyped) - TESTBALL_URL = ::T.let(nil, ::T.untyped) - TEST_DIRECTORIES = ::T.let(nil, ::T.untyped) TEST_FIXTURE_DIR = ::T.let(nil, ::T.untyped) TEST_SHA1 = ::T.let(nil, ::T.untyped) TEST_SHA256 = ::T.let(nil, ::T.untyped) @@ -13479,6 +13689,10 @@ class Object def self.yaml_tag(url); end end +module ObserverPathnameExtension + extend ::T::Private::Methods::SingletonMethodHooks +end + class OpenSSL::ASN1::ASN1Data def indefinite_length(); end @@ -13509,11 +13723,7 @@ class OpenSSL::KDF::KDFError end module OpenSSL::KDF - def self.hkdf(*_); end - def self.pbkdf2_hmac(*_); end - - def self.scrypt(*_); end end class OpenSSL::OCSP::Request @@ -13522,29 +13732,20 @@ end OpenSSL::PKCS7::Signer = OpenSSL::PKCS7::SignerInfo -class OpenSSL::PKey::EC - EXPLICIT_CURVE = ::T.let(nil, ::T.untyped) -end - class OpenSSL::PKey::EC::Point def to_octet_string(_); end end module OpenSSL::SSL - OP_ALLOW_NO_DHE_KEX = ::T.let(nil, ::T.untyped) OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = ::T.let(nil, ::T.untyped) OP_CRYPTOPRO_TLSEXT_BUG = ::T.let(nil, ::T.untyped) OP_LEGACY_SERVER_CONNECT = ::T.let(nil, ::T.untyped) - OP_NO_ENCRYPT_THEN_MAC = ::T.let(nil, ::T.untyped) - OP_NO_RENEGOTIATION = ::T.let(nil, ::T.untyped) - OP_NO_TLSv1_3 = ::T.let(nil, ::T.untyped) OP_SAFARI_ECDHE_ECDSA_BUG = ::T.let(nil, ::T.untyped) OP_TLSEXT_PADDING = ::T.let(nil, ::T.untyped) SSL2_VERSION = ::T.let(nil, ::T.untyped) SSL3_VERSION = ::T.let(nil, ::T.untyped) TLS1_1_VERSION = ::T.let(nil, ::T.untyped) TLS1_2_VERSION = ::T.let(nil, ::T.untyped) - TLS1_3_VERSION = ::T.let(nil, ::T.untyped) TLS1_VERSION = ::T.let(nil, ::T.untyped) end @@ -13559,8 +13760,6 @@ class OpenSSL::SSL::SSLContext def alpn_select_cb=(alpn_select_cb); end - def enable_fallback_scsv(); end - def max_version=(version); end def min_version=(version); end @@ -13660,7 +13859,12 @@ module OpenURI def self.scan_open_optional_arguments(*rest); end end -class OsxfuseRequirement +class Option + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class Options extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks end @@ -15141,8 +15345,8 @@ class Parser::Ruby26 end class Pathname - include ::ELFShim include ::MachOShim + include ::ELFShim def fnmatch?(*_); end def glob(*_); end @@ -15150,6 +15354,11 @@ class Pathname def make_symlink(_); end end +class Pathname + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class PkgVersion def major(*args, &block); end @@ -22218,16 +22427,12 @@ module RSpec::Matchers def a_hash_including(*args, &block); end - def a_json_string(*expected, &block_arg); end - def a_kind_of(*args, &block); end def a_nil_value(*args, &block); end def a_range_covering(*args, &block); end - def a_string_containing(*args, &block); end - def a_string_ending_with(*args, &block); end def a_string_including(*args, &block); end @@ -22266,14 +22471,10 @@ module RSpec::Matchers def an_object_satisfying(*args, &block); end - def array_including_cons(*expected, &block_arg); end - def be(*args); end def be_a(klass); end - def be_a_failure(*args, &block); end - def be_a_kind_of(expected); end def be_an(klass); end @@ -22332,8 +22533,6 @@ module RSpec::Matchers def have_attributes(expected); end - def have_failed(*args, &block); end - def having_attributes(*args, &block); end def include(*expected); end @@ -22348,8 +22547,6 @@ module RSpec::Matchers def matching(*args, &block); end - def not_to_output(*args, &block); end - def output(expected=T.unsafe(nil)); end def raise_error(error=T.unsafe(nil), message=T.unsafe(nil), &block); end @@ -25199,6 +25396,25 @@ end RSpec::SharedContext = RSpec::Core::SharedContext +module RSpec::Sorbet +end + +module RSpec::Sorbet::Doubles + def allow_doubles!(); end + + def allow_instance_doubles!(); end + INLINE_DOUBLE_REGEX = ::T.let(nil, ::T.untyped) + TYPED_ARRAY_MESSAGE = ::T.let(nil, ::T.untyped) + VERIFYING_DOUBLE_OR_DOUBLE = ::T.let(nil, ::T.untyped) +end + +module RSpec::Sorbet::Doubles +end + +module RSpec::Sorbet + extend ::RSpec::Sorbet::Doubles +end + module RSpec::Support DEFAULT_FAILURE_NOTIFIER = ::T.let(nil, ::T.untyped) DEFAULT_WARNING_NOTIFIER = ::T.let(nil, ::T.untyped) @@ -25848,11 +26064,9 @@ class Regexp::Expression::CharacterSet include ::RuboCop::Ext::RegexpParser::Expression::CharacterSet end -class ReporterHub - def empty?(*args, &block); end -end - class Requirement + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks def self.cask(val=T.unsafe(nil)); end def self.download(val=T.unsafe(nil)); end @@ -25860,6 +26074,11 @@ class Requirement def self.fatal(val=T.unsafe(nil)); end end +class Requirements + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Resolv::DNS def extract_resources(msg, name, typeclass); end @@ -25953,6 +26172,11 @@ class ResourceStageContext def version(*args, &block); end end +class ResourceStageContext + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Ronn REV = ::T.let(nil, ::T.untyped) VERSION = ::T.let(nil, ::T.untyped) @@ -26245,12 +26469,18 @@ module RuboCop::AST::NodePattern::Sets SET_INCLUDE_WITH_WITHOUT = ::T.let(nil, ::T.untyped) SET_SYSTEM_SHELL_OUTPUT_PIPE_OUTPUT = ::T.let(nil, ::T.untyped) SET_WITH_WITHOUT = ::T.let(nil, ::T.untyped) + SET___METHOD_____CALLEE__ = ::T.let(nil, ::T.untyped) end class RuboCop::Cask::AST::CaskBlock def cask_body(*args, &block); end end +class RuboCop::Cask::AST::CaskHeader + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class RuboCop::Cask::AST::Stanza def app?(); end @@ -26357,6 +26587,11 @@ class RuboCop::Cop::Cask::NoDslVersion def preferred_header_str(*args, &block); end end +class RuboCop::Cop::Cask::NoDslVersion + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module RuboCop::Cop::Cask::OnDescStanza def toplevel_stanzas(*args, &block); end end @@ -26445,6 +26680,16 @@ class RuboCop::Cop::FormulaAudit::Patches def patch_data?(param0); end end +class RuboCop::Cop::FormulaAudit::Patches + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class RuboCop::Cop::FormulaAudit::PyPiUrls + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class RuboCop::Cop::FormulaAudit::Test def test_calls(param0); end end @@ -27484,6 +27729,11 @@ class RubyVM def self.resolve_feature_path(_); end end +class Sandbox + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + ScanError = StringScanner::Error class Set @@ -27517,6 +27767,11 @@ module SharedEnvExtension def llvm_clang(); end end +module SharedEnvExtension + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module SimpleCov VERSION = ::T.let(nil, ::T.untyped) end @@ -28285,36 +28540,188 @@ module Singleton def self.__init__(klass); end end -class SoftwareSpec - def cached_download(*args, &block); end +class Socket + AF_CCITT = ::T.let(nil, ::T.untyped) + AF_CHAOS = ::T.let(nil, ::T.untyped) + AF_CNT = ::T.let(nil, ::T.untyped) + AF_COIP = ::T.let(nil, ::T.untyped) + AF_DATAKIT = ::T.let(nil, ::T.untyped) + AF_DLI = ::T.let(nil, ::T.untyped) + AF_E164 = ::T.let(nil, ::T.untyped) + AF_ECMA = ::T.let(nil, ::T.untyped) + AF_HYLINK = ::T.let(nil, ::T.untyped) + AF_IMPLINK = ::T.let(nil, ::T.untyped) + AF_ISO = ::T.let(nil, ::T.untyped) + AF_LAT = ::T.let(nil, ::T.untyped) + AF_LINK = ::T.let(nil, ::T.untyped) + AF_NATM = ::T.let(nil, ::T.untyped) + AF_NDRV = ::T.let(nil, ::T.untyped) + AF_NETBIOS = ::T.let(nil, ::T.untyped) + AF_NS = ::T.let(nil, ::T.untyped) + AF_OSI = ::T.let(nil, ::T.untyped) + AF_PPP = ::T.let(nil, ::T.untyped) + AF_PUP = ::T.let(nil, ::T.untyped) + AF_SIP = ::T.let(nil, ::T.untyped) + AF_SYSTEM = ::T.let(nil, ::T.untyped) + AI_DEFAULT = ::T.let(nil, ::T.untyped) + AI_MASK = ::T.let(nil, ::T.untyped) + AI_V4MAPPED_CFG = ::T.let(nil, ::T.untyped) + EAI_BADHINTS = ::T.let(nil, ::T.untyped) + EAI_MAX = ::T.let(nil, ::T.untyped) + EAI_PROTOCOL = ::T.let(nil, ::T.untyped) + IFF_ALTPHYS = ::T.let(nil, ::T.untyped) + IFF_LINK0 = ::T.let(nil, ::T.untyped) + IFF_LINK1 = ::T.let(nil, ::T.untyped) + IFF_LINK2 = ::T.let(nil, ::T.untyped) + IFF_OACTIVE = ::T.let(nil, ::T.untyped) + IFF_SIMPLEX = ::T.let(nil, ::T.untyped) + IPPROTO_EON = ::T.let(nil, ::T.untyped) + IPPROTO_GGP = ::T.let(nil, ::T.untyped) + IPPROTO_HELLO = ::T.let(nil, ::T.untyped) + IPPROTO_MAX = ::T.let(nil, ::T.untyped) + IPPROTO_ND = ::T.let(nil, ::T.untyped) + IPPROTO_XTP = ::T.let(nil, ::T.untyped) + IPV6_DONTFRAG = ::T.let(nil, ::T.untyped) + IPV6_PATHMTU = ::T.let(nil, ::T.untyped) + IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped) + IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped) + IP_DONTFRAG = ::T.let(nil, ::T.untyped) + IP_PORTRANGE = ::T.let(nil, ::T.untyped) + IP_RECVDSTADDR = ::T.let(nil, ::T.untyped) + IP_RECVIF = ::T.let(nil, ::T.untyped) + LOCAL_PEERCRED = ::T.let(nil, ::T.untyped) + MSG_EOF = ::T.let(nil, ::T.untyped) + MSG_FLUSH = ::T.let(nil, ::T.untyped) + MSG_HAVEMORE = ::T.let(nil, ::T.untyped) + MSG_HOLD = ::T.let(nil, ::T.untyped) + MSG_RCVMORE = ::T.let(nil, ::T.untyped) + MSG_SEND = ::T.let(nil, ::T.untyped) + PF_CCITT = ::T.let(nil, ::T.untyped) + PF_CHAOS = ::T.let(nil, ::T.untyped) + PF_CNT = ::T.let(nil, ::T.untyped) + PF_COIP = ::T.let(nil, ::T.untyped) + PF_DATAKIT = ::T.let(nil, ::T.untyped) + PF_DLI = ::T.let(nil, ::T.untyped) + PF_ECMA = ::T.let(nil, ::T.untyped) + PF_HYLINK = ::T.let(nil, ::T.untyped) + PF_IMPLINK = ::T.let(nil, ::T.untyped) + PF_ISO = ::T.let(nil, ::T.untyped) + PF_LAT = ::T.let(nil, ::T.untyped) + PF_LINK = ::T.let(nil, ::T.untyped) + PF_NATM = ::T.let(nil, ::T.untyped) + PF_NDRV = ::T.let(nil, ::T.untyped) + PF_NETBIOS = ::T.let(nil, ::T.untyped) + PF_NS = ::T.let(nil, ::T.untyped) + PF_OSI = ::T.let(nil, ::T.untyped) + PF_PIP = ::T.let(nil, ::T.untyped) + PF_PPP = ::T.let(nil, ::T.untyped) + PF_PUP = ::T.let(nil, ::T.untyped) + PF_RTIP = ::T.let(nil, ::T.untyped) + PF_SIP = ::T.let(nil, ::T.untyped) + PF_SYSTEM = ::T.let(nil, ::T.untyped) + PF_XTP = ::T.let(nil, ::T.untyped) + SCM_CREDS = ::T.let(nil, ::T.untyped) + SO_DONTTRUNC = ::T.let(nil, ::T.untyped) + SO_NKE = ::T.let(nil, ::T.untyped) + SO_NOSIGPIPE = ::T.let(nil, ::T.untyped) + SO_NREAD = ::T.let(nil, ::T.untyped) + SO_USELOOPBACK = ::T.let(nil, ::T.untyped) + SO_WANTMORE = ::T.let(nil, ::T.untyped) + SO_WANTOOBFLAG = ::T.let(nil, ::T.untyped) + TCP_NOOPT = ::T.let(nil, ::T.untyped) + TCP_NOPUSH = ::T.let(nil, ::T.untyped) +end - def checksum(*args, &block); end - - def clear_cache(*args, &block); end - - def download_name(*args, &block); end - - def downloader(*args, &block); end - - def fetch(*args, &block); end - - def mirror(*args, &block); end - - def mirrors(*args, &block); end - - def sha256(*args, &block); end - - def source_modified_time(*args, &block); end - - def specs(*args, &block); end - - def stage(*args, &block); end - - def using(*args, &block); end - - def verify_download_integrity(*args, &block); end - - def version(*args, &block); end +module Socket::Constants + AF_CCITT = ::T.let(nil, ::T.untyped) + AF_CHAOS = ::T.let(nil, ::T.untyped) + AF_CNT = ::T.let(nil, ::T.untyped) + AF_COIP = ::T.let(nil, ::T.untyped) + AF_DATAKIT = ::T.let(nil, ::T.untyped) + AF_DLI = ::T.let(nil, ::T.untyped) + AF_E164 = ::T.let(nil, ::T.untyped) + AF_ECMA = ::T.let(nil, ::T.untyped) + AF_HYLINK = ::T.let(nil, ::T.untyped) + AF_IMPLINK = ::T.let(nil, ::T.untyped) + AF_ISO = ::T.let(nil, ::T.untyped) + AF_LAT = ::T.let(nil, ::T.untyped) + AF_LINK = ::T.let(nil, ::T.untyped) + AF_NATM = ::T.let(nil, ::T.untyped) + AF_NDRV = ::T.let(nil, ::T.untyped) + AF_NETBIOS = ::T.let(nil, ::T.untyped) + AF_NS = ::T.let(nil, ::T.untyped) + AF_OSI = ::T.let(nil, ::T.untyped) + AF_PPP = ::T.let(nil, ::T.untyped) + AF_PUP = ::T.let(nil, ::T.untyped) + AF_SIP = ::T.let(nil, ::T.untyped) + AF_SYSTEM = ::T.let(nil, ::T.untyped) + AI_DEFAULT = ::T.let(nil, ::T.untyped) + AI_MASK = ::T.let(nil, ::T.untyped) + AI_V4MAPPED_CFG = ::T.let(nil, ::T.untyped) + EAI_BADHINTS = ::T.let(nil, ::T.untyped) + EAI_MAX = ::T.let(nil, ::T.untyped) + EAI_PROTOCOL = ::T.let(nil, ::T.untyped) + IFF_ALTPHYS = ::T.let(nil, ::T.untyped) + IFF_LINK0 = ::T.let(nil, ::T.untyped) + IFF_LINK1 = ::T.let(nil, ::T.untyped) + IFF_LINK2 = ::T.let(nil, ::T.untyped) + IFF_OACTIVE = ::T.let(nil, ::T.untyped) + IFF_SIMPLEX = ::T.let(nil, ::T.untyped) + IPPROTO_EON = ::T.let(nil, ::T.untyped) + IPPROTO_GGP = ::T.let(nil, ::T.untyped) + IPPROTO_HELLO = ::T.let(nil, ::T.untyped) + IPPROTO_MAX = ::T.let(nil, ::T.untyped) + IPPROTO_ND = ::T.let(nil, ::T.untyped) + IPPROTO_XTP = ::T.let(nil, ::T.untyped) + IPV6_DONTFRAG = ::T.let(nil, ::T.untyped) + IPV6_PATHMTU = ::T.let(nil, ::T.untyped) + IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped) + IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped) + IP_DONTFRAG = ::T.let(nil, ::T.untyped) + IP_PORTRANGE = ::T.let(nil, ::T.untyped) + IP_RECVDSTADDR = ::T.let(nil, ::T.untyped) + IP_RECVIF = ::T.let(nil, ::T.untyped) + LOCAL_PEERCRED = ::T.let(nil, ::T.untyped) + MSG_EOF = ::T.let(nil, ::T.untyped) + MSG_FLUSH = ::T.let(nil, ::T.untyped) + MSG_HAVEMORE = ::T.let(nil, ::T.untyped) + MSG_HOLD = ::T.let(nil, ::T.untyped) + MSG_RCVMORE = ::T.let(nil, ::T.untyped) + MSG_SEND = ::T.let(nil, ::T.untyped) + PF_CCITT = ::T.let(nil, ::T.untyped) + PF_CHAOS = ::T.let(nil, ::T.untyped) + PF_CNT = ::T.let(nil, ::T.untyped) + PF_COIP = ::T.let(nil, ::T.untyped) + PF_DATAKIT = ::T.let(nil, ::T.untyped) + PF_DLI = ::T.let(nil, ::T.untyped) + PF_ECMA = ::T.let(nil, ::T.untyped) + PF_HYLINK = ::T.let(nil, ::T.untyped) + PF_IMPLINK = ::T.let(nil, ::T.untyped) + PF_ISO = ::T.let(nil, ::T.untyped) + PF_LAT = ::T.let(nil, ::T.untyped) + PF_LINK = ::T.let(nil, ::T.untyped) + PF_NATM = ::T.let(nil, ::T.untyped) + PF_NDRV = ::T.let(nil, ::T.untyped) + PF_NETBIOS = ::T.let(nil, ::T.untyped) + PF_NS = ::T.let(nil, ::T.untyped) + PF_OSI = ::T.let(nil, ::T.untyped) + PF_PIP = ::T.let(nil, ::T.untyped) + PF_PPP = ::T.let(nil, ::T.untyped) + PF_PUP = ::T.let(nil, ::T.untyped) + PF_RTIP = ::T.let(nil, ::T.untyped) + PF_SIP = ::T.let(nil, ::T.untyped) + PF_SYSTEM = ::T.let(nil, ::T.untyped) + PF_XTP = ::T.let(nil, ::T.untyped) + SCM_CREDS = ::T.let(nil, ::T.untyped) + SO_DONTTRUNC = ::T.let(nil, ::T.untyped) + SO_NKE = ::T.let(nil, ::T.untyped) + SO_NOSIGPIPE = ::T.let(nil, ::T.untyped) + SO_NREAD = ::T.let(nil, ::T.untyped) + SO_USELOOPBACK = ::T.let(nil, ::T.untyped) + SO_WANTMORE = ::T.let(nil, ::T.untyped) + SO_WANTOOBFLAG = ::T.let(nil, ::T.untyped) + TCP_NOOPT = ::T.let(nil, ::T.untyped) + TCP_NOPUSH = ::T.let(nil, ::T.untyped) end class SortedSet @@ -28371,6 +28778,11 @@ module Stdenv def Os(); end end +module Stdenv + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class String include ::String::Compat def acts_like_string?(); end @@ -28568,6 +28980,11 @@ class String ENCODED_BLANKS = ::T.let(nil, ::T.untyped) end +class String + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class StringInreplaceExtension extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks @@ -28667,6 +29084,11 @@ module Superenv def Os(); end end +module Superenv + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class SynchronizedDelegator def method_missing(method, *args, &block); end @@ -28679,24 +29101,69 @@ class SynchronizedDelegator end class SystemCommand - def must_succeed?(); end - - def print_stderr?(); end - - def print_stdout?(); end - - def sudo?(); end + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks end module TZInfo end +class TZInfo::AbsoluteDayOfYearTransitionRule + def get_day(year); end + + def initialize(day, transition_at=T.unsafe(nil)); end + + def is_always_first_day_of_year?(); end + + def is_always_last_day_of_year?(); end +end + +class TZInfo::AbsoluteDayOfYearTransitionRule +end + class TZInfo::AmbiguousTime end class TZInfo::AmbiguousTime end +class TZInfo::AnnualRules + def dst_end_rule(); end + + def dst_offset(); end + + def dst_start_rule(); end + + def initialize(std_offset, dst_offset, dst_start_rule, dst_end_rule); end + + def std_offset(); end + + def transitions(year); end +end + +class TZInfo::AnnualRules::Transition + def at(); end + + def at=(_); end + + def offset(); end + + def offset=(_); end + + def previous_offset(); end + + def previous_offset=(_); end +end + +class TZInfo::AnnualRules::Transition + def self.[](*_); end + + def self.members(); end +end + +class TZInfo::AnnualRules +end + class TZInfo::Country include ::Comparable def _dump(limit); end @@ -28834,6 +29301,41 @@ end class TZInfo::DataTimezoneInfo end +class TZInfo::DayOfMonthTransitionRule + def get_day(year); end + + def initialize(month, week, day_of_week, transition_at=T.unsafe(nil)); end + + def offset_start(); end +end + +class TZInfo::DayOfMonthTransitionRule +end + +class TZInfo::DayOfWeekTransitionRule + def day_of_week(); end + + def initialize(month, day_of_week, transition_at); end + + def is_always_first_day_of_year?(); end + + def is_always_last_day_of_year?(); end + + def month(); end +end + +class TZInfo::DayOfWeekTransitionRule +end + +class TZInfo::DayOfYearTransitionRule + def initialize(day, transition_at); end + + def seconds(); end +end + +class TZInfo::DayOfYearTransitionRule +end + class TZInfo::InfoTimezone def info(); end @@ -28856,6 +29358,12 @@ end class TZInfo::InvalidDataSource end +class TZInfo::InvalidPosixTimeZone +end + +class TZInfo::InvalidPosixTimeZone +end + class TZInfo::InvalidTimezoneIdentifier end @@ -28874,6 +29382,30 @@ end class TZInfo::InvalidZoneinfoFile end +class TZInfo::JulianDayOfYearTransitionRule + def get_day(year); end + + def initialize(day, transition_at=T.unsafe(nil)); end + + def is_always_first_day_of_year?(); end + + def is_always_last_day_of_year?(); end + LEAP = ::T.let(nil, ::T.untyped) + YEAR = ::T.let(nil, ::T.untyped) +end + +class TZInfo::JulianDayOfYearTransitionRule +end + +class TZInfo::LastDayOfMonthTransitionRule + def get_day(year); end + + def initialize(month, day_of_week, transition_at=T.unsafe(nil)); end +end + +class TZInfo::LastDayOfMonthTransitionRule +end + class TZInfo::LinkedTimezone end @@ -28908,6 +29440,13 @@ end class TZInfo::PeriodNotFound end +class TZInfo::PosixTimeZoneParser + def parse(tz_string); end +end + +class TZInfo::PosixTimeZoneParser +end + module TZInfo::RubyCoreSupport HALF_DAYS_IN_DAY = ::T.let(nil, ::T.untyped) end @@ -28988,6 +29527,8 @@ class TZInfo::TimeOrDateTime def usec(); end + def wday(); end + def year(); end end @@ -29276,6 +29817,25 @@ end class TZInfo::TransitionDataTimezoneInfo end +class TZInfo::TransitionRule + def ==(r); end + + def at(offset, year); end + + def eql?(r); end + + def hash_args(); end + + def initialize(transition_at); end + + def new_time_or_datetime(year, month=T.unsafe(nil), day=T.unsafe(nil)); end + + def transition_at(); end +end + +class TZInfo::TransitionRule +end + class TZInfo::UnknownTimezone end @@ -29316,7 +29876,8 @@ class TZInfo::ZoneinfoDirectoryNotFound end class TZInfo::ZoneinfoTimezoneInfo - def initialize(identifier, file_path); end + def initialize(identifier, file_path, posix_tz_parser); end + GENERATE_UP_TO = ::T.let(nil, ::T.untyped) MAX_TIMESTAMP = ::T.let(nil, ::T.untyped) MIN_TIMESTAMP = ::T.let(nil, ::T.untyped) end @@ -29327,6 +29888,11 @@ end module TZInfo end +class Tab + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class Tapioca::Compilers::Dsl::Base extend ::T::Sig extend ::T::Helpers @@ -30081,6 +30647,96 @@ end module UnicodeNormalize end +class UnpackStrategy::Air + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Bzip2 + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Cab + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Directory + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Dmg + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Fossil + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::GenericUnar + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Gzip + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Lha + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Lzip + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Lzma + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::P7Zip + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Pax + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Rar + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Tar + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Uncompressed + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Xar + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +class UnpackStrategy::Xz + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class UnpackStrategy::Zip include ::UnpackStrategy::Zip::MacOSZipExtension end @@ -30123,11 +30779,30 @@ class Utils::Bottles::Collector def keys(*args, &block); end end +class Utils::Bottles::Collector + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module Utils::Bottles + extend ::T::Private::Methods::SingletonMethodHooks +end + module Utils::Inreplace extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks end +class Utils::Shebang::RewriteInfo + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + +module Utils::Shebang + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Utils::Shell extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks @@ -30137,6 +30812,11 @@ module Utils::Svn extend ::T::Private::Methods::SingletonMethodHooks end +class Version::Token + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + module Warning extend ::Warning end @@ -30165,14 +30845,10 @@ module Zeitwerk::ExplicitNamespace extend ::Zeitwerk::RealModName def self.cpaths(); end - def self.disable_tracer_if_unneeded(); end - def self.mutex(); end def self.register(cpath, loader); end - def self.tracepoint_class_callback(event); end - def self.tracer(); end def self.unregister(loader); end diff --git a/Library/Homebrew/sorbet/rbi/upstream.rbi b/Library/Homebrew/sorbet/rbi/upstream.rbi new file mode 100644 index 0000000000..d3295ae20c --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/upstream.rbi @@ -0,0 +1,11 @@ +# typed: strict + +class Pathname + # https://github.com/sorbet/sorbet/pull/3676 + sig { params(p1: T.any(String, Pathname), p2: String).returns(T::Array[Pathname]) } + def self.glob(p1, p2 = T.unsafe(nil)); end + + # https://github.com/sorbet/sorbet/pull/3678 + sig { params(with_directory: T::Boolean).returns(T::Array[Pathname]) } + def children(with_directory = true); end +end diff --git a/Library/Homebrew/sorbet/triggers.yml b/Library/Homebrew/sorbet/triggers.yml index 52bc3b2aea..48a007d979 100644 --- a/Library/Homebrew/sorbet/triggers.yml +++ b/Library/Homebrew/sorbet/triggers.yml @@ -3,3 +3,4 @@ ruby_extra_args: triggers: using: sorbet/plugins/unpack_strategy_magic.rb + attr_predicate: sorbet/plugins/attr_predicate.rb diff --git a/Library/Homebrew/style.rb b/Library/Homebrew/style.rb index 40a11b50cf..3f10decf18 100644 --- a/Library/Homebrew/style.rb +++ b/Library/Homebrew/style.rb @@ -269,6 +269,8 @@ module Homebrew # Source location of a style offense. class LineLocation + extend T::Sig + attr_reader :line, :column def initialize(json) @@ -276,6 +278,7 @@ module Homebrew @column = json["column"] end + sig { returns(String) } def to_s "#{line}: col #{column}" end diff --git a/Library/Homebrew/system_command.rb b/Library/Homebrew/system_command.rb index 3d83ec5c0a..a9ef6cf6b5 100644 --- a/Library/Homebrew/system_command.rb +++ b/Library/Homebrew/system_command.rb @@ -15,6 +15,8 @@ using HashValidator # # @api private class SystemCommand + extend T::Sig + # Helper functions for calling {SystemCommand.run}. module Mixin def system_command(*args) @@ -39,6 +41,7 @@ class SystemCommand run(command, **options, must_succeed: true) end + sig { returns(SystemCommand::Result) } def run! puts redact_secrets(command.shelljoin.gsub('\=', "="), @secrets) if verbose? || debug? diff --git a/Library/Homebrew/system_config.rb b/Library/Homebrew/system_config.rb index 02230bb9b4..6702c71635 100644 --- a/Library/Homebrew/system_config.rb +++ b/Library/Homebrew/system_config.rb @@ -12,6 +12,8 @@ require "system_command" # @api private module SystemConfig class << self + extend T::Sig + include SystemCommand::Mixin def clang @@ -30,34 +32,42 @@ module SystemConfig end end + sig { returns(String) } def head HOMEBREW_REPOSITORY.git_head || "(none)" end + sig { returns(String) } def last_commit HOMEBREW_REPOSITORY.git_last_commit || "never" end + sig { returns(String) } def origin HOMEBREW_REPOSITORY.git_origin || "(none)" end + sig { returns(String) } def core_tap_head CoreTap.instance.git_head || "(none)" end + sig { returns(String) } def core_tap_last_commit CoreTap.instance.git_last_commit || "never" end + sig { returns(String) } def core_tap_branch CoreTap.instance.git_branch || "(none)" end + sig { returns(String) } def core_tap_origin CoreTap.instance.remote || "(none)" end + sig { returns(String) } def describe_clang return "N/A" if clang.null? @@ -76,6 +86,7 @@ module SystemConfig end end + sig { returns(String) } def describe_homebrew_ruby_version case RUBY_VERSION when /^1\.[89]/, /^2\.0/ @@ -85,20 +96,24 @@ module SystemConfig end end + sig { returns(String) } def describe_homebrew_ruby "#{describe_homebrew_ruby_version} => #{RUBY_PATH}" end + sig { returns(T.nilable(String)) } def hardware return if Hardware::CPU.type == :dunno "CPU: #{Hardware.cores_as_words}-core #{Hardware::CPU.bits}-bit #{Hardware::CPU.family}" end + sig { returns(String) } def kernel `uname -m`.chomp end + sig { returns(String) } def describe_java return "N/A" unless which "java" @@ -108,12 +123,14 @@ module SystemConfig err[/java version "([\d._]+)"/, 1] || "N/A" end + sig { returns(String) } def describe_git return "N/A" unless Utils::Git.available? "#{Utils::Git.version} => #{Utils::Git.path}" end + sig { returns(String) } def describe_curl out, = system_command(curl_executable, args: ["--version"]) diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb index 4d6a4a7728..8b732cae14 100644 --- a/Library/Homebrew/tab.rb +++ b/Library/Homebrew/tab.rb @@ -12,6 +12,8 @@ require "extend/cachable" # hash and creates an attribute for each key and value. Rather than calling # `new` directly, use one of the class methods like {Tab.create}. class Tab < OpenStruct + extend T::Sig + extend Cachable FILENAME = "INSTALL_RECEIPT.json" @@ -324,6 +326,7 @@ class Tab < OpenStruct versions["version_scheme"] || 0 end + sig { returns(Time) } def source_modified_time Time.at(super || 0) end @@ -362,6 +365,7 @@ class Tab < OpenStruct tabfile.atomic_write(to_json) end + sig { returns(String) } def to_s s = [] s << if poured_from_bottle diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 3e40bad395..d4a33d8ab7 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -12,6 +12,8 @@ require "description_cache_store" # {#user} represents the GitHub username and {#repo} represents the repository # name without the leading `homebrew-`. class Tap + extend T::Sig + extend Cachable TAP_DIRECTORY = (HOMEBREW_LIBRARY/"Taps").freeze @@ -123,6 +125,7 @@ class Tap end # The default remote path to this {Tap}. + sig { returns(String) } def default_remote "https://github.com/#{full_name}" end @@ -176,6 +179,7 @@ class Tap # The issues URL of this {Tap}. # e.g. `https://github.com/user/homebrew-repo/issues` + sig { returns(T.nilable(String)) } def issues_url return unless official? || !custom_remote? @@ -186,6 +190,7 @@ class Tap name end + sig { returns(String) } def version_string return "N/A" unless installed? @@ -227,6 +232,7 @@ class Tap end # @private + sig { returns(T::Boolean) } def core_tap? false end @@ -580,7 +586,7 @@ class Tap def self.each(&block) return unless TAP_DIRECTORY.directory? - return to_enum unless block_given? + return to_enum unless block TAP_DIRECTORY.subdirs.each do |user| user.subdirs.each do |repo| @@ -595,6 +601,7 @@ class Tap end # An array of all tap cmd directory {Pathname}s. + sig { returns(T::Array[Pathname]) } def self.cmd_directories Pathname.glob TAP_DIRECTORY/"*/*/cmd" end @@ -633,7 +640,10 @@ end # A specialized {Tap} class for the core formulae. class CoreTap < Tap + extend T::Sig + # @private + sig { void } def initialize super "Homebrew", "core" end @@ -660,26 +670,31 @@ class CoreTap < Tap end # @private + sig { void } def uninstall raise "Tap#uninstall is not available for CoreTap" end # @private + sig { void } def pin raise "Tap#pin is not available for CoreTap" end # @private + sig { void } def unpin raise "Tap#unpin is not available for CoreTap" end # @private + sig { returns(T::Boolean) } def pinned? false end # @private + sig { returns(T::Boolean) } def core_tap? true end diff --git a/Library/Homebrew/tap_auditor.rb b/Library/Homebrew/tap_auditor.rb new file mode 100644 index 0000000000..c38e9abaf6 --- /dev/null +++ b/Library/Homebrew/tap_auditor.rb @@ -0,0 +1,72 @@ +# typed: true +# frozen_string_literal: true + +module Homebrew + # Auditor for checking common violations in {Tap}s. + # + # @api private + class TapAuditor + extend T::Sig + + attr_reader :name, :path, :tap_audit_exceptions, :problems + + sig { params(tap: Tap, strict: T::Boolean).void } + def initialize(tap, strict:) + @name = tap.name + @path = tap.path + @tap_audit_exceptions = tap.audit_exceptions + @problems = [] + end + + sig { void } + def audit + audit_json_files + audit_tap_audit_exceptions + end + + sig { void } + def audit_json_files + json_patterns = Tap::HOMEBREW_TAP_JSON_FILES.map { |pattern| @path/pattern } + Pathname.glob(json_patterns).each do |file| + JSON.parse file.read + rescue JSON::ParserError + problem "#{file.to_s.delete_prefix("#{@path}/")} contains invalid JSON" + end + end + + sig { void } + def audit_tap_audit_exceptions + @tap_audit_exceptions.each do |list_name, formula_names| + unless [Hash, Array].include? formula_names.class + problem <<~EOS + audit_exceptions/#{list_name}.json should contain a JSON array + of formula names or a JSON object mapping formula names to values + EOS + next + end + + formula_names = formula_names.keys if formula_names.is_a? Hash + + invalid_formulae = [] + formula_names.each do |name| + invalid_formulae << name if Formula[name].tap != @name + rescue FormulaUnavailableError + invalid_formulae << name + end + + next if invalid_formulae.empty? + + problem <<~EOS + audit_exceptions/#{list_name}.json references + formulae that are not found in the #{@name} tap. + Invalid formulae: #{invalid_formulae.join(", ")} + EOS + end + end + + sig { params(message: String).void } + def problem(message) + @problems << ({ message: message, location: nil }) + end + end +end diff --git a/Library/Homebrew/test/bintray_spec.rb b/Library/Homebrew/test/bintray_spec.rb index 8e17b2d9f3..be7f3f47ba 100644 --- a/Library/Homebrew/test/bintray_spec.rb +++ b/Library/Homebrew/test/bintray_spec.rb @@ -17,7 +17,7 @@ describe Bintray, :needs_network do expect(hash).to eq("449de5ea35d0e9431f367f1bb34392e450f6853cdccdc6bd04e6ad6471904ddb") end - it "fails on a non-existant file" do + it "fails on a non-existent file" do hash = bintray.remote_checksum(repo: "bottles", remote_file: "my-fake-bottle-1.0.snow_hyena.tar.gz") expect(hash).to be nil end diff --git a/Library/Homebrew/test/cli/named_args_spec.rb b/Library/Homebrew/test/cli/named_args_spec.rb index 29af7187e1..b8efc96cde 100644 --- a/Library/Homebrew/test/cli/named_args_spec.rb +++ b/Library/Homebrew/test/cli/named_args_spec.rb @@ -150,16 +150,16 @@ describe Homebrew::CLI::NamedArgs do expect(described_class.new("foo", "baz").to_paths).to eq [formula_path, cask_path] end - it "returns only formulae when `only: :formulae` is specified" do + it "returns only formulae when `only: :formula` is specified" do expect(Formulary).to receive(:path).with("foo").and_return(formula_path) - expect(described_class.new("foo", "baz").to_paths(only: :formulae)).to eq [formula_path, Formulary.path("baz")] + expect(described_class.new("foo", "baz").to_paths(only: :formula)).to eq [formula_path, Formulary.path("baz")] end - it "returns only casks when `only: :casks` is specified" do + it "returns only casks when `only: :cask` is specified" do expect(Cask::CaskLoader).to receive(:path).with("foo").and_return(cask_path) - expect(described_class.new("foo", "baz").to_paths(only: :casks)).to eq [cask_path, Cask::CaskLoader.path("baz")] + expect(described_class.new("foo", "baz").to_paths(only: :cask)).to eq [cask_path, Cask::CaskLoader.path("baz")] end end end diff --git a/Library/Homebrew/test/cli/parser_spec.rb b/Library/Homebrew/test/cli/parser_spec.rb index 7f1c71c3ad..e5fae5af8e 100644 --- a/Library/Homebrew/test/cli/parser_spec.rb +++ b/Library/Homebrew/test/cli/parser_spec.rb @@ -62,7 +62,7 @@ describe Homebrew::CLI::Parser do it "passes through invalid options" do args = parser.parse(["-v", "named-arg", "--not-a-valid-option"], ignore_invalid_options: true) expect(args.remaining).to eq ["named-arg", "--not-a-valid-option"] - expect(args.named_args).to be_empty + expect(args.named).to be_empty end end diff --git a/Library/Homebrew/test/cmd/--cache_spec.rb b/Library/Homebrew/test/cmd/--cache_spec.rb index 6f8acbb945..c7e9e5dc82 100644 --- a/Library/Homebrew/test/cmd/--cache_spec.rb +++ b/Library/Homebrew/test/cmd/--cache_spec.rb @@ -10,14 +10,14 @@ end describe "brew --cache", :integration_test do it "prints all cache files for a given Formula" do expect { brew "--cache", testball } - .to output(%r{#{HOMEBREW_CACHE}/downloads/[\da-f]{64}--testball-}).to_stdout + .to output(%r{#{HOMEBREW_CACHE}/downloads/[\da-f]{64}--testball-}o).to_stdout .and not_to_output.to_stderr .and be_a_success end it "prints the cache files for a given Cask" do expect { brew "--cache", cask_path("local-caffeine") } - .to output(%r{#{HOMEBREW_CACHE}/downloads/[\da-f]{64}--caffeine\.zip}).to_stdout + .to output(%r{#{HOMEBREW_CACHE}/downloads/[\da-f]{64}--caffeine\.zip}o).to_stdout .and not_to_output.to_stderr .and be_a_success end @@ -28,7 +28,7 @@ describe "brew --cache", :integration_test do %r{ #{HOMEBREW_CACHE}/downloads/[\da-f]{64}--testball-.*\n #{HOMEBREW_CACHE}/downloads/[\da-f]{64}--caffeine\.zip - }x, + }xo, ).to_stdout .and not_to_output.to_stderr .and be_a_success diff --git a/Library/Homebrew/test/cmd/--cellar_spec.rb b/Library/Homebrew/test/cmd/--cellar_spec.rb index 1bda2bd9f9..c558c684a8 100644 --- a/Library/Homebrew/test/cmd/--cellar_spec.rb +++ b/Library/Homebrew/test/cmd/--cellar_spec.rb @@ -10,7 +10,7 @@ end describe "brew --cellar", :integration_test do it "returns the Cellar subdirectory for a given Formula" do expect { brew "--cellar", testball } - .to output(%r{#{HOMEBREW_CELLAR}/testball}).to_stdout + .to output(%r{#{HOMEBREW_CELLAR}/testball}o).to_stdout .and not_to_output.to_stderr .and be_a_success end diff --git a/Library/Homebrew/test/cmd/--prefix_spec.rb b/Library/Homebrew/test/cmd/--prefix_spec.rb index 527581f5f5..95ac7bb042 100644 --- a/Library/Homebrew/test/cmd/--prefix_spec.rb +++ b/Library/Homebrew/test/cmd/--prefix_spec.rb @@ -10,7 +10,7 @@ end describe "brew --prefix", :integration_test do it "prints a given Formula's prefix" do expect { brew "--prefix", testball } - .to output(%r{#{HOMEBREW_CELLAR}/testball}).to_stdout + .to output(%r{#{HOMEBREW_CELLAR}/testball}o).to_stdout .and not_to_output.to_stderr .and be_a_success end diff --git a/Library/Homebrew/test/cmd/--version_spec.rb b/Library/Homebrew/test/cmd/--version_spec.rb index 7d9d71cd8b..11e91912e8 100644 --- a/Library/Homebrew/test/cmd/--version_spec.rb +++ b/Library/Homebrew/test/cmd/--version_spec.rb @@ -10,7 +10,7 @@ end describe "brew --version", :integration_test do it "prints the Homebrew version" do expect { brew "--version" } - .to output(/^Homebrew #{Regexp.escape(HOMEBREW_VERSION)}\n/).to_stdout + .to output(/^Homebrew #{Regexp.escape(HOMEBREW_VERSION)}\n/o).to_stdout .and not_to_output.to_stderr .and be_a_success end diff --git a/Library/Homebrew/test/cmd/cleanup_spec.rb b/Library/Homebrew/test/cmd/cleanup_spec.rb index 437f8a6277..d1906e5562 100644 --- a/Library/Homebrew/test/cmd/cleanup_spec.rb +++ b/Library/Homebrew/test/cmd/cleanup_spec.rb @@ -22,7 +22,7 @@ describe "brew cleanup", :integration_test do (HOMEBREW_CACHE/"test").write "test" expect { brew "cleanup", "--prune=all" } - .to output(%r{#{Regexp.escape(HOMEBREW_CACHE)}/test}).to_stdout + .to output(%r{#{Regexp.escape(HOMEBREW_CACHE)}/test}o).to_stdout .and not_to_output.to_stderr .and be_a_success end diff --git a/Library/Homebrew/test/cmd/config_spec.rb b/Library/Homebrew/test/cmd/config_spec.rb index df5bed7910..843c2a52a5 100644 --- a/Library/Homebrew/test/cmd/config_spec.rb +++ b/Library/Homebrew/test/cmd/config_spec.rb @@ -10,7 +10,7 @@ end describe "brew config", :integration_test do it "prints information about the current Homebrew configuration" do expect { brew "config" } - .to output(/HOMEBREW_VERSION: #{Regexp.escape HOMEBREW_VERSION}/).to_stdout + .to output(/HOMEBREW_VERSION: #{Regexp.escape HOMEBREW_VERSION}/o).to_stdout .and not_to_output.to_stderr .and be_a_success end diff --git a/Library/Homebrew/test/cmd/install_spec.rb b/Library/Homebrew/test/cmd/install_spec.rb index ef100add41..c17cc00ee7 100644 --- a/Library/Homebrew/test/cmd/install_spec.rb +++ b/Library/Homebrew/test/cmd/install_spec.rb @@ -12,7 +12,7 @@ describe "brew install", :integration_test do setup_test_formula "testball1" expect { brew "install", "testball1" } - .to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}).to_stdout + .to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}o).to_stdout .and not_to_output.to_stderr .and be_a_success expect(HOMEBREW_CELLAR/"testball1/0.1/foo/test").not_to be_a_file @@ -22,7 +22,7 @@ describe "brew install", :integration_test do setup_test_formula "testball1" expect { brew "install", "testball1", "--with-foo" } - .to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}).to_stdout + .to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}o).to_stdout .and not_to_output.to_stderr .and be_a_success expect(HOMEBREW_CELLAR/"testball1/0.1/foo/test").to be_a_file @@ -36,7 +36,7 @@ describe "brew install", :integration_test do RUBY expect { brew "install", "testball1" } - .to output(%r{#{HOMEBREW_CELLAR}/testball1/1\.0}).to_stdout + .to output(%r{#{HOMEBREW_CELLAR}/testball1/1\.0}o).to_stdout .and not_to_output.to_stderr .and be_a_success expect(HOMEBREW_CELLAR/"testball1/1.0/foo/test").not_to be_a_file @@ -69,7 +69,7 @@ describe "brew install", :integration_test do # and there will be the git requirement, but we cannot instantiate git # formula since we only have testball1 formula. expect { brew "install", "testball1", "--HEAD", "--ignore-dependencies" } - .to output(%r{#{HOMEBREW_CELLAR}/testball1/HEAD-d5eb689}).to_stdout + .to output(%r{#{HOMEBREW_CELLAR}/testball1/HEAD-d5eb689}o).to_stdout .and output(/Cloning into/).to_stderr .and be_a_success expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file diff --git a/Library/Homebrew/test/dev-cmd/audit_spec.rb b/Library/Homebrew/test/dev-cmd/audit_spec.rb index a283686f3d..4548be2e0f 100644 --- a/Library/Homebrew/test/dev-cmd/audit_spec.rb +++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb @@ -18,7 +18,7 @@ module Count end module Homebrew - describe FormulaText do + describe FormulaTextAuditor do alias_matcher :have_data, :be_data alias_matcher :have_end, :be_end alias_matcher :have_trailing_newline, :be_trailing_newline @@ -717,6 +717,19 @@ module Homebrew it { is_expected.to be_nil } end + + context "can be removed when switching schemes" do + before do + formula_gsub_origin_commit( + 'url "https://brew.sh/foo-1.0.tar.gz"', + 'url "https://foo.com/brew/bar.git", tag: "1.0", revision: "f5e00e485e7aa4c5baa20355b27e3b84a6912790"', + ) + formula_gsub_origin_commit('sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e"', + "") + end + + it { is_expected.to be_nil } + end end context "revisions" do diff --git a/Library/Homebrew/test/dev-cmd/command_spec.rb b/Library/Homebrew/test/dev-cmd/command_spec.rb index 5e6ecdfbe9..87c9dd61f3 100644 --- a/Library/Homebrew/test/dev-cmd/command_spec.rb +++ b/Library/Homebrew/test/dev-cmd/command_spec.rb @@ -10,7 +10,7 @@ end describe "brew command", :integration_test do it "returns the file for a given command" do expect { brew "command", "info" } - .to output(%r{#{Regexp.escape(HOMEBREW_LIBRARY_PATH)}/cmd/info.rb}).to_stdout + .to output(%r{#{Regexp.escape(HOMEBREW_LIBRARY_PATH)}/cmd/info.rb}o).to_stdout .and be_a_success end end diff --git a/Library/Homebrew/test/diagnostic_checks_spec.rb b/Library/Homebrew/test/diagnostic_checks_spec.rb index bd2c17beca..72a23e16d9 100644 --- a/Library/Homebrew/test/diagnostic_checks_spec.rb +++ b/Library/Homebrew/test/diagnostic_checks_spec.rb @@ -66,7 +66,7 @@ describe Homebrew::Diagnostic::Checks do specify "#check_user_path_2" do ENV["PATH"] = ENV["PATH"].gsub \ - %r{(?:^|#{File::PATH_SEPARATOR})#{HOMEBREW_PREFIX}/bin}, "" + %r{(?:^|#{File::PATH_SEPARATOR})#{HOMEBREW_PREFIX}/bin}o, "" expect(subject.check_user_path_1).to be nil expect(subject.check_user_path_2) diff --git a/Library/Homebrew/test/exceptions_spec.rb b/Library/Homebrew/test/exceptions_spec.rb index e938c843c7..fee12d3fbb 100644 --- a/Library/Homebrew/test/exceptions_spec.rb +++ b/Library/Homebrew/test/exceptions_spec.rb @@ -48,12 +48,12 @@ describe FormulaUnavailableError do it "returns a string if there is a dependent" do subject.dependent = "foobar" - expect(subject.dependent_s).to eq("(dependency of foobar)") + expect(subject.dependent_s).to eq(" (dependency of foobar)") end end context "without a dependent" do - its(:to_s) { is_expected.to eq('No available formula with the name "foo" ') } + its(:to_s) { is_expected.to eq('No available formula with the name "foo".') } end context "with a dependent" do @@ -62,7 +62,7 @@ describe FormulaUnavailableError do end its(:to_s) { - expect(subject.to_s).to eq('No available formula with the name "foo" (dependency of foobar)') + expect(subject.to_s).to eq('No available formula with the name "foo" (dependency of foobar).') } end end diff --git a/Library/Homebrew/test/language/java_spec.rb b/Library/Homebrew/test/language/java_spec.rb index 4893a272ce..52613697e0 100644 --- a/Library/Homebrew/test/language/java_spec.rb +++ b/Library/Homebrew/test/language/java_spec.rb @@ -5,9 +5,11 @@ require "language/java" describe Language::Java do describe "::java_home" do - it "returns valid JAVA_HOME if version is specified", :needs_java do - java_home = described_class.java_home("1.6+") - expect(java_home/"bin/java").to be_an_executable + if !OS.mac? || MacOS.version < :big_sur + it "returns valid JAVA_HOME if version is specified", :needs_java do + java_home = described_class.java_home("1.6+") + expect(java_home/"bin/java").to be_an_executable + end end it "returns valid JAVA_HOME if version is not specified", :needs_java do diff --git a/Library/Homebrew/test/language/node_spec.rb b/Library/Homebrew/test/language/node_spec.rb index 0785f105a9..44ce3faad1 100644 --- a/Library/Homebrew/test/language/node_spec.rb +++ b/Library/Homebrew/test/language/node_spec.rb @@ -4,6 +4,8 @@ require "language/node" describe Language::Node do + let(:npm_pack_cmd) { "npm pack --ignore-scripts" } + describe "#setup_npm_environment" do it "calls prepend_path when node formula exists only during the first call" do node = formula "node" do @@ -25,22 +27,21 @@ describe Language::Node do end describe "#std_pack_for_installation" do - npm_pack_cmd = "npm pack --ignore-scripts" - it "removes prepare and prepack scripts" do - path = Pathname("package.json") - path.atomic_write("{\"scripts\":{\"prepare\": \"ls\", \"prepack\": \"ls\", \"test\": \"ls\"}}") - allow(Utils).to receive(:popen_read).with(npm_pack_cmd).and_return(`echo pack.tgz`) - subject.pack_for_installation - expect(path.read).not_to include("prepare") - expect(path.read).not_to include("prepack") - expect(path.read).to include("test") + mktmpdir.cd do + path = Pathname("package.json") + path.atomic_write("{\"scripts\":{\"prepare\": \"ls\", \"prepack\": \"ls\", \"test\": \"ls\"}}") + allow(Utils).to receive(:popen_read).with(npm_pack_cmd).and_return(`echo pack.tgz`) + subject.pack_for_installation + expect(path.read).not_to include("prepare") + expect(path.read).not_to include("prepack") + expect(path.read).to include("test") + end end end describe "#std_npm_install_args" do npm_install_arg = Pathname("libexec") - npm_pack_cmd = "npm pack --ignore-scripts" it "raises error with non zero exitstatus" do allow(Utils).to receive(:popen_read).with(npm_pack_cmd).and_return(`false`) diff --git a/Library/Homebrew/test/livecheck/livecheck_spec.rb b/Library/Homebrew/test/livecheck/livecheck_spec.rb index 5bbd943203..edf2d27216 100644 --- a/Library/Homebrew/test/livecheck/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck/livecheck_spec.rb @@ -29,6 +29,15 @@ describe Homebrew::Livecheck do end end + let(:f_disabled) do + formula("test_disabled") do + desc "Disabled test formula" + homepage "https://brew.sh" + url "https://brew.sh/test-0.0.1.tgz" + disable! because: :unmaintained + end + end + let(:f_gist) do formula("test_gist") do desc "Gist test formula" @@ -100,6 +109,12 @@ describe Homebrew::Livecheck do .and not_to_output.to_stderr end + it "skips a disabled formula without a livecheckable" do + expect { livecheck.skip_conditions(f_disabled, args: args) } + .to output("test_disabled : disabled\n").to_stdout + .and not_to_output.to_stderr + end + it "skips a versioned formula without a livecheckable" do expect { livecheck.skip_conditions(f_versioned, args: args) } .to output("test@0.0.1 : versioned\n").to_stdout @@ -139,11 +154,51 @@ describe Homebrew::Livecheck do end describe "::preprocess_url" do - let(:url) { "https://github.s3.amazonaws.com/downloads/Homebrew/brew/1.0.0.tar.gz" } + let(:github_git_url_with_extension) { "https://github.com/Homebrew/brew.git" } - it "returns the preprocessed URL for livecheck to use" do - expect(livecheck.preprocess_url(url)) - .to eq("https://github.com/Homebrew/brew.git") + it "returns the unmodified URL for a GitHub URL ending in .git" do + expect(livecheck.preprocess_url(github_git_url_with_extension)) + .to eq(github_git_url_with_extension) + end + + it "returns the Git repository URL for a GitHub URL not ending in .git" do + expect(livecheck.preprocess_url("https://github.com/Homebrew/brew")) + .to eq(github_git_url_with_extension) + end + + it "returns the unmodified URL for a GitHub /releases/latest URL" do + expect(livecheck.preprocess_url("https://github.com/Homebrew/brew/releases/latest")) + .to eq("https://github.com/Homebrew/brew/releases/latest") + end + + it "returns the Git repository URL for a GitHub AWS URL" do + expect(livecheck.preprocess_url("https://github.s3.amazonaws.com/downloads/Homebrew/brew/1.0.0.tar.gz")) + .to eq(github_git_url_with_extension) + end + + it "returns the Git repository URL for a github.com/downloads/... URL" do + expect(livecheck.preprocess_url("https://github.com/downloads/Homebrew/brew/1.0.0.tar.gz")) + .to eq(github_git_url_with_extension) + end + + it "returns the Git repository URL for a GitHub tag archive URL" do + expect(livecheck.preprocess_url("https://github.com/Homebrew/brew/archive/1.0.0.tar.gz")) + .to eq(github_git_url_with_extension) + end + + it "returns the Git repository URL for a GitHub release archive URL" do + expect(livecheck.preprocess_url("https://github.com/Homebrew/brew/releases/download/1.0.0/brew-1.0.0.tar.gz")) + .to eq(github_git_url_with_extension) + end + + it "returns the Git repository URL for a gitlab.com archive URL" do + expect(livecheck.preprocess_url("https://gitlab.com/Homebrew/brew/-/archive/1.0.0/brew-1.0.0.tar.gz")) + .to eq("https://gitlab.com/Homebrew/brew.git") + end + + it "returns the Git repository URL for a self-hosted GitLab archive URL" do + expect(livecheck.preprocess_url("https://brew.sh/Homebrew/brew/-/archive/1.0.0/brew-1.0.0.tar.gz")) + .to eq("https://brew.sh/Homebrew/brew.git") end end end diff --git a/Library/Homebrew/test/requirements/java_requirement_spec.rb b/Library/Homebrew/test/requirements/java_requirement_spec.rb index 8c709270b3..a33c25928c 100644 --- a/Library/Homebrew/test/requirements/java_requirement_spec.rb +++ b/Library/Homebrew/test/requirements/java_requirement_spec.rb @@ -68,9 +68,11 @@ describe JavaRequirement do describe "#satisfied?" do subject(:requirement) { described_class.new(%w[1.8]) } - it "returns false if no `java` executable can be found" do - allow(File).to receive(:executable?).and_return(false) - expect(requirement).not_to be_satisfied + if !OS.mac? || MacOS.version < :big_sur + it "returns false if no `java` executable can be found" do + allow(File).to receive(:executable?).and_return(false) + expect(requirement).not_to be_satisfied + end end it "returns true if #preferred_java returns a path" do diff --git a/Library/Homebrew/test/rubocop_spec.rb b/Library/Homebrew/test/rubocop_spec.rb index 83ae2ddf68..1526df7506 100644 --- a/Library/Homebrew/test/rubocop_spec.rb +++ b/Library/Homebrew/test/rubocop_spec.rb @@ -10,11 +10,12 @@ describe "RuboCop" do ENV.delete(key) if key.start_with?("HOMEBREW_") end - ENV["XDG_CACHE_HOME"] = "#{HOMEBREW_CACHE}/style" + ENV["XDG_CACHE_HOME"] = (HOMEBREW_CACHE.realpath/"style").to_s end it "loads all Formula cops without errors" do - stdout, _, status = Open3.capture3("rubocop", TEST_FIXTURE_DIR/"testball.rb") + stdout, stderr, status = Open3.capture3("rubocop", TEST_FIXTURE_DIR/"testball.rb") + expect(stderr).to be_empty expect(stdout).to include("no offenses detected") expect(status).to be_a_success end diff --git a/Library/Homebrew/test/rubocops/components_order_spec.rb b/Library/Homebrew/test/rubocops/components_order_spec.rb index 098e782546..8aa6bfc867 100644 --- a/Library/Homebrew/test/rubocops/components_order_spec.rb +++ b/Library/Homebrew/test/rubocops/components_order_spec.rb @@ -225,6 +225,31 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do corrected_source = autocorrect_source(source) expect(corrected_source).to eq(correct_source) end + + it "When `depends_on` precedes `deprecate!`" do + source = <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + + depends_on "openssl" + + deprecate! because: "has been replaced by bar" + end + RUBY + + correct_source = <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + + deprecate! because: "has been replaced by bar" + + depends_on "openssl" + end + RUBY + + corrected_source = autocorrect_source(source) + expect(corrected_source).to eq(correct_source) + end end context "no on_os_block" do diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 91697e5218..85e9f65de4 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -26,6 +26,7 @@ end require "rspec/its" require "rspec/wait" require "rspec/retry" +require "rspec/sorbet" require "rubocop" require "rubocop/rspec/support" require "find" @@ -58,6 +59,10 @@ TEST_DIRECTORIES = [ HOMEBREW_TEMP, ].freeze +# Make `instance_double` and `class_double` +# work when type-checking is active. +RSpec::Sorbet.allow_doubles! + RSpec.configure do |config| config.order = :random @@ -78,7 +83,8 @@ RSpec.configure do |config| config.default_retry_count = 2 config.around(:each, :needs_network) do |example| - example.run_with_retry retry: 3, retry_wait: 3 + example.metadata[:timeout] ||= 120 + example.run_with_retry retry: 5, retry_wait: 5 end end @@ -109,7 +115,7 @@ RSpec.configure do |config| config.before(:each, :needs_java) do java_installed = if OS.mac? - Utils.popen_read("/usr/libexec/java_home", "--failfast", "--version", "1.0+") + Utils.popen_read("/usr/libexec/java_home", "--failfast") $CHILD_STATUS.success? else which("java") diff --git a/Library/Homebrew/test/support/fixtures/cask/Casks/with-conditional-caveats.rb b/Library/Homebrew/test/support/fixtures/cask/Casks/with-conditional-caveats.rb index 265bd7757d..3f26d9c19a 100644 --- a/Library/Homebrew/test/support/fixtures/cask/Casks/with-conditional-caveats.rb +++ b/Library/Homebrew/test/support/fixtures/cask/Casks/with-conditional-caveats.rb @@ -9,6 +9,6 @@ cask "with-conditional-caveats" do # a do block may print and use a DSL caveats do - puts "This caveat is conditional" if false # rubocop:disable Lint/LiteralAsCondition + puts "This caveat is conditional" unless String("Caffeine") == "Caffeine" end end diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb index 3d18361e9b..9f9e6e576d 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb @@ -151,7 +151,7 @@ RSpec.shared_context "integration test" do # something here RUBY - when "foo" + when "foo", "patchelf" content = <<~RUBY url "https://brew.sh/#{name}-1.0" RUBY @@ -160,11 +160,6 @@ RSpec.shared_context "integration test" do url "https://brew.sh/#{name}-1.0" depends_on "foo" RUBY - when "patchelf" - content = <<~RUBY - url "https://brew.sh/#{name}-1.0" - RUBY - when "package_license" content = <<~RUBY url "https://brew.sh/#patchelf-1.0" @@ -183,8 +178,7 @@ RSpec.shared_context "integration test" do def install_test_formula(name, content = nil, build_bottle: false) setup_test_formula(name, content) - fi = FormulaInstaller.new(Formula[name]) - fi.build_bottle = build_bottle + fi = FormulaInstaller.new(Formula[name], build_bottle: build_bottle) fi.prelude fi.fetch fi.install diff --git a/Library/Homebrew/test/utils/github_spec.rb b/Library/Homebrew/test/utils/github_spec.rb index 3ee58750d0..1949123d28 100644 --- a/Library/Homebrew/test/utils/github_spec.rb +++ b/Library/Homebrew/test/utils/github_spec.rb @@ -54,7 +54,7 @@ describe GitHub do it "errors on an unauthenticated token" do expect { subject.sponsors_by_tier("Homebrew") - }.to raise_error(/INSUFFICIENT_SCOPES|FORBIDDEN/) + }.to raise_error(/INSUFFICIENT_SCOPES|FORBIDDEN|token needs the 'admin:org' scope/) end end diff --git a/Library/Homebrew/test/utils/shell_spec.rb b/Library/Homebrew/test/utils/shell_spec.rb index 61c24e745f..3db721c63f 100644 --- a/Library/Homebrew/test/utils/shell_spec.rb +++ b/Library/Homebrew/test/utils/shell_spec.rb @@ -73,7 +73,7 @@ describe Utils::Shell do specify "::csh_quote" do expect(subject.send(:csh_quote, "")).to eq("''") expect(subject.send(:csh_quote, "\\")).to eq("\\\\") - # note this test is different than for sh + # NOTE: this test is different than for sh expect(subject.send(:csh_quote, "\n")).to eq("'\\\n'") expect(subject.send(:csh_quote, "$")).to eq("\\$") expect(subject.send(:csh_quote, "word")).to eq("word") diff --git a/Library/Homebrew/unlink.rb b/Library/Homebrew/unlink.rb index bd265d5c5c..47384433e3 100644 --- a/Library/Homebrew/unlink.rb +++ b/Library/Homebrew/unlink.rb @@ -8,6 +8,7 @@ module Homebrew def unlink_versioned_formulae(formula, verbose: false) formula.versioned_formulae + .select(&:keg_only?) .select(&:linked?) .map(&:any_installed_keg) .compact diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index c187be8286..1e0ece5101 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -47,6 +47,7 @@ module UnpackStrategy Tar, # Needs to be before Bzip2/Gzip/Xz/Lzma. Pax, Gzip, + Dmg, # Needs to be before Bzip2/Xz/Lzma. Lzma, Xz, Lzip, @@ -66,7 +67,6 @@ module UnpackStrategy SelfExtractingExecutable, # Needs to be before `Cab`. Cab, Executable, - Dmg, # Needs to be before `Bzip2`. Bzip2, Fossil, Bazaar, diff --git a/Library/Homebrew/unpack_strategy/air.rb b/Library/Homebrew/unpack_strategy/air.rb index 8d6e73cd1c..9f8bd8c473 100644 --- a/Library/Homebrew/unpack_strategy/air.rb +++ b/Library/Homebrew/unpack_strategy/air.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking Adobe Air archives. class Air + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".air"] end @@ -28,6 +31,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! AIR_APPLICATION_INSTALLER, args: ["-silent", "-location", unpack_dir, path], diff --git a/Library/Homebrew/unpack_strategy/bazaar.rb b/Library/Homebrew/unpack_strategy/bazaar.rb index f50957a124..12fbd503d0 100644 --- a/Library/Homebrew/unpack_strategy/bazaar.rb +++ b/Library/Homebrew/unpack_strategy/bazaar.rb @@ -6,6 +6,8 @@ require_relative "directory" module UnpackStrategy # Strategy for unpacking Bazaar archives. class Bazaar < Directory + extend T::Sig + using Magic def self.can_extract?(path) @@ -14,11 +16,12 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) super # The export command doesn't work on checkouts (see https://bugs.launchpad.net/bzr/+bug/897511). - FileUtils.rm_r unpack_dir/".bzr" + (unpack_dir/".bzr").rmtree end end end diff --git a/Library/Homebrew/unpack_strategy/bzip2.rb b/Library/Homebrew/unpack_strategy/bzip2.rb index 79d25aaa5b..6b05e4dc15 100644 --- a/Library/Homebrew/unpack_strategy/bzip2.rb +++ b/Library/Homebrew/unpack_strategy/bzip2.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking bzip2 archives. class Bzip2 + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".bz2"] end @@ -18,6 +21,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) FileUtils.cp path, unpack_dir/basename, preserve: true quiet_flags = verbose ? [] : ["-q"] diff --git a/Library/Homebrew/unpack_strategy/cab.rb b/Library/Homebrew/unpack_strategy/cab.rb index 00b0831288..89feaf0df6 100644 --- a/Library/Homebrew/unpack_strategy/cab.rb +++ b/Library/Homebrew/unpack_strategy/cab.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking Cabinet archives. class Cab + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".cab"] end @@ -16,6 +19,7 @@ module UnpackStrategy path.magic_number.match?(/\AMSCF/n) end + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "cabextract", args: ["-d", unpack_dir, "--", path], diff --git a/Library/Homebrew/unpack_strategy/compress.rb b/Library/Homebrew/unpack_strategy/compress.rb index 8e83fa057a..65f9ea8728 100644 --- a/Library/Homebrew/unpack_strategy/compress.rb +++ b/Library/Homebrew/unpack_strategy/compress.rb @@ -6,8 +6,11 @@ require_relative "tar" module UnpackStrategy # Strategy for unpacking compress archives. class Compress < Tar + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".Z"] end diff --git a/Library/Homebrew/unpack_strategy/directory.rb b/Library/Homebrew/unpack_strategy/directory.rb index 0e8c68b593..02772dcc68 100644 --- a/Library/Homebrew/unpack_strategy/directory.rb +++ b/Library/Homebrew/unpack_strategy/directory.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking directories. class Directory + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [] end @@ -18,6 +21,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) path.children.each do |child| system_command! "cp", diff --git a/Library/Homebrew/unpack_strategy/dmg.rb b/Library/Homebrew/unpack_strategy/dmg.rb index 1d2e8de5ce..db6f3285d5 100644 --- a/Library/Homebrew/unpack_strategy/dmg.rb +++ b/Library/Homebrew/unpack_strategy/dmg.rb @@ -6,6 +6,8 @@ require "tempfile" module UnpackStrategy # Strategy for unpacking disk images. class Dmg + extend T::Sig + include UnpackStrategy # Helper module for listing the contents of a volume mounted from a disk image. @@ -54,6 +56,8 @@ module UnpackStrategy # Strategy for unpacking a volume mounted from a disk image. class Mount + extend T::Sig + using Bom include UnpackStrategy @@ -82,6 +86,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) Tempfile.open(["", ".bom"]) do |bomfile| bomfile.close @@ -105,6 +110,7 @@ module UnpackStrategy end private_constant :Mount + sig { returns(T::Array[String]) } def self.extensions [".dmg"] end @@ -116,6 +122,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) mount(verbose: verbose) do |mounts| raise "No mounts found in '#{path}'; perhaps this is a bad disk image?" if mounts.empty? diff --git a/Library/Homebrew/unpack_strategy/executable.rb b/Library/Homebrew/unpack_strategy/executable.rb index a592cce52f..1daeb7d0f7 100644 --- a/Library/Homebrew/unpack_strategy/executable.rb +++ b/Library/Homebrew/unpack_strategy/executable.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking executables. class Executable < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".sh", ".bash"] end diff --git a/Library/Homebrew/unpack_strategy/fossil.rb b/Library/Homebrew/unpack_strategy/fossil.rb index f421ee1be8..869a056285 100644 --- a/Library/Homebrew/unpack_strategy/fossil.rb +++ b/Library/Homebrew/unpack_strategy/fossil.rb @@ -6,11 +6,14 @@ require "system_command" module UnpackStrategy # Strategy for unpacking Fossil repositories. class Fossil + extend T::Sig + include UnpackStrategy extend SystemCommand::Mixin using Magic + sig { returns(T::Array[String]) } def self.extensions [] end @@ -25,6 +28,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) args = if @ref_type && @ref [@ref] diff --git a/Library/Homebrew/unpack_strategy/generic_unar.rb b/Library/Homebrew/unpack_strategy/generic_unar.rb index 7b0a0a53bd..4628cd517d 100644 --- a/Library/Homebrew/unpack_strategy/generic_unar.rb +++ b/Library/Homebrew/unpack_strategy/generic_unar.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking archives with `unar`. class GenericUnar + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [] end @@ -22,6 +25,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "unar", args: [ diff --git a/Library/Homebrew/unpack_strategy/gzip.rb b/Library/Homebrew/unpack_strategy/gzip.rb index 4797fbaa24..983d995a98 100644 --- a/Library/Homebrew/unpack_strategy/gzip.rb +++ b/Library/Homebrew/unpack_strategy/gzip.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking gzip archives. class Gzip + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".gz"] end @@ -18,6 +21,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) FileUtils.cp path, unpack_dir/basename, preserve: true quiet_flags = verbose ? [] : ["-q"] diff --git a/Library/Homebrew/unpack_strategy/jar.rb b/Library/Homebrew/unpack_strategy/jar.rb index ee05a876a1..d4170a8689 100644 --- a/Library/Homebrew/unpack_strategy/jar.rb +++ b/Library/Homebrew/unpack_strategy/jar.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking Java archives. class Jar < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".apk", ".jar"] end diff --git a/Library/Homebrew/unpack_strategy/lha.rb b/Library/Homebrew/unpack_strategy/lha.rb index 70c3e5f709..7b92af7290 100644 --- a/Library/Homebrew/unpack_strategy/lha.rb +++ b/Library/Homebrew/unpack_strategy/lha.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking LHa archives. class Lha + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".lha", ".lzh"] end @@ -22,6 +25,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "lha", args: ["xq2w=#{unpack_dir}", path], diff --git a/Library/Homebrew/unpack_strategy/lua_rock.rb b/Library/Homebrew/unpack_strategy/lua_rock.rb index 1336b856de..6150e2788e 100644 --- a/Library/Homebrew/unpack_strategy/lua_rock.rb +++ b/Library/Homebrew/unpack_strategy/lua_rock.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking LuaRock archives. class LuaRock < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".rock"] end diff --git a/Library/Homebrew/unpack_strategy/lzip.rb b/Library/Homebrew/unpack_strategy/lzip.rb index a27663e4d5..71f561c9df 100644 --- a/Library/Homebrew/unpack_strategy/lzip.rb +++ b/Library/Homebrew/unpack_strategy/lzip.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking lzip archives. class Lzip + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".lz"] end @@ -22,6 +25,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) FileUtils.cp path, unpack_dir/basename, preserve: true quiet_flags = verbose ? [] : ["-q"] diff --git a/Library/Homebrew/unpack_strategy/lzma.rb b/Library/Homebrew/unpack_strategy/lzma.rb index e14de8e993..b8ee36b210 100644 --- a/Library/Homebrew/unpack_strategy/lzma.rb +++ b/Library/Homebrew/unpack_strategy/lzma.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking LZMA archives. class Lzma + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".lzma"] end @@ -16,6 +19,13 @@ module UnpackStrategy path.magic_number.match?(/\A\]\000\000\200\000/n) end + def dependencies + @dependencies ||= [Formula["xz"]] + end + + private + + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) FileUtils.cp path, unpack_dir/basename, preserve: true quiet_flags = verbose ? [] : ["-q"] @@ -24,9 +34,5 @@ module UnpackStrategy env: { "PATH" => PATH.new(Formula["xz"].opt_bin, ENV["PATH"]) }, verbose: verbose end - - def dependencies - @dependencies ||= [Formula["xz"]] - end end end diff --git a/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb b/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb index 5d97e6f222..616d78bc06 100644 --- a/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb +++ b/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking Microsoft Office documents. class MicrosoftOfficeXml < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [ ".doc", ".docx", diff --git a/Library/Homebrew/unpack_strategy/otf.rb b/Library/Homebrew/unpack_strategy/otf.rb index 1a0538d942..e94eb15029 100644 --- a/Library/Homebrew/unpack_strategy/otf.rb +++ b/Library/Homebrew/unpack_strategy/otf.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking OpenType fonts. class Otf < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".otf"] end diff --git a/Library/Homebrew/unpack_strategy/p7zip.rb b/Library/Homebrew/unpack_strategy/p7zip.rb index 5aca009f53..3a5ef46f00 100644 --- a/Library/Homebrew/unpack_strategy/p7zip.rb +++ b/Library/Homebrew/unpack_strategy/p7zip.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking P7ZIP archives. class P7Zip + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".7z"] end @@ -22,6 +25,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "7zr", args: ["x", "-y", "-bd", "-bso0", path, "-o#{unpack_dir}"], diff --git a/Library/Homebrew/unpack_strategy/pax.rb b/Library/Homebrew/unpack_strategy/pax.rb index e914d41baf..4067132c80 100644 --- a/Library/Homebrew/unpack_strategy/pax.rb +++ b/Library/Homebrew/unpack_strategy/pax.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking pax archives. class Pax + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".pax"] end @@ -18,6 +21,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "pax", args: ["-rf", path], diff --git a/Library/Homebrew/unpack_strategy/pkg.rb b/Library/Homebrew/unpack_strategy/pkg.rb index 20bf5057e8..220b86a58c 100644 --- a/Library/Homebrew/unpack_strategy/pkg.rb +++ b/Library/Homebrew/unpack_strategy/pkg.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking macOS package installers. class Pkg < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".pkg", ".mkpg"] end diff --git a/Library/Homebrew/unpack_strategy/rar.rb b/Library/Homebrew/unpack_strategy/rar.rb index 71e2dd66a2..7cd1d02635 100644 --- a/Library/Homebrew/unpack_strategy/rar.rb +++ b/Library/Homebrew/unpack_strategy/rar.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking RAR archives. class Rar + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".rar"] end @@ -22,6 +25,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "unrar", args: ["x", "-inul", path, unpack_dir], diff --git a/Library/Homebrew/unpack_strategy/self_extracting_executable.rb b/Library/Homebrew/unpack_strategy/self_extracting_executable.rb index c74166d771..0e99278711 100644 --- a/Library/Homebrew/unpack_strategy/self_extracting_executable.rb +++ b/Library/Homebrew/unpack_strategy/self_extracting_executable.rb @@ -6,8 +6,11 @@ require_relative "generic_unar" module UnpackStrategy # Strategy for unpacking self-extracting executables. class SelfExtractingExecutable < GenericUnar + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [] end diff --git a/Library/Homebrew/unpack_strategy/sit.rb b/Library/Homebrew/unpack_strategy/sit.rb index 5fabbbbfc8..687e7d0e64 100644 --- a/Library/Homebrew/unpack_strategy/sit.rb +++ b/Library/Homebrew/unpack_strategy/sit.rb @@ -6,8 +6,11 @@ require_relative "generic_unar" module UnpackStrategy # Strategy for unpacking Stuffit archives. class Sit < GenericUnar + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".sit"] end diff --git a/Library/Homebrew/unpack_strategy/tar.rb b/Library/Homebrew/unpack_strategy/tar.rb index a31550b75d..a40ad8f45e 100644 --- a/Library/Homebrew/unpack_strategy/tar.rb +++ b/Library/Homebrew/unpack_strategy/tar.rb @@ -6,11 +6,14 @@ require "system_command" module UnpackStrategy # Strategy for unpacking tar archives. class Tar + extend T::Sig + include UnpackStrategy extend SystemCommand::Mixin using Magic + sig { returns(T::Array[String]) } def self.extensions [ ".tar", @@ -33,6 +36,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) Dir.mktmpdir do |tmpdir| tar_path = path diff --git a/Library/Homebrew/unpack_strategy/ttf.rb b/Library/Homebrew/unpack_strategy/ttf.rb index b45755a428..38b44879de 100644 --- a/Library/Homebrew/unpack_strategy/ttf.rb +++ b/Library/Homebrew/unpack_strategy/ttf.rb @@ -6,8 +6,11 @@ require_relative "uncompressed" module UnpackStrategy # Strategy for unpacking TrueType fonts. class Ttf < Uncompressed + extend T::Sig + using Magic + sig { returns(T::Array[String]) } def self.extensions [".ttc", ".ttf"] end diff --git a/Library/Homebrew/unpack_strategy/uncompressed.rb b/Library/Homebrew/unpack_strategy/uncompressed.rb index 1c869d998e..16ced6ca16 100644 --- a/Library/Homebrew/unpack_strategy/uncompressed.rb +++ b/Library/Homebrew/unpack_strategy/uncompressed.rb @@ -4,6 +4,8 @@ module UnpackStrategy # Strategy for unpacking uncompressed files. class Uncompressed + extend T::Sig + include UnpackStrategy def extract_nestedly(prioritise_extension: false, **options) @@ -12,6 +14,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) FileUtils.cp path, unpack_dir/basename, preserve: true, verbose: verbose end diff --git a/Library/Homebrew/unpack_strategy/xar.rb b/Library/Homebrew/unpack_strategy/xar.rb index 2f5f4794a3..ce35a0683a 100644 --- a/Library/Homebrew/unpack_strategy/xar.rb +++ b/Library/Homebrew/unpack_strategy/xar.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking xar archives. class Xar + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".xar"] end @@ -18,6 +21,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) system_command! "xar", args: ["-x", "-f", path, "-C", unpack_dir], diff --git a/Library/Homebrew/unpack_strategy/xz.rb b/Library/Homebrew/unpack_strategy/xz.rb index 86f50d2a38..ec81be5673 100644 --- a/Library/Homebrew/unpack_strategy/xz.rb +++ b/Library/Homebrew/unpack_strategy/xz.rb @@ -4,10 +4,13 @@ module UnpackStrategy # Strategy for unpacking xz archives. class Xz + extend T::Sig + include UnpackStrategy using Magic + sig { returns(T::Array[String]) } def self.extensions [".xz"] end @@ -22,6 +25,7 @@ module UnpackStrategy private + sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } def extract_to_dir(unpack_dir, basename:, verbose:) FileUtils.cp path, unpack_dir/basename, preserve: true quiet_flags = verbose ? [] : ["-q"] diff --git a/Library/Homebrew/upgrade.rb b/Library/Homebrew/upgrade.rb index 1fa4e8313f..02a0af9a77 100644 --- a/Library/Homebrew/upgrade.rb +++ b/Library/Homebrew/upgrade.rb @@ -67,20 +67,23 @@ module Homebrew options |= f.build.used_options options &= f.options - fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?, - build_from_source_formulae: args.build_from_source_formulae, - debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?) - fi.options = options - fi.force = args.force? - fi.keep_tmp = args.keep_tmp? - fi.build_bottle = args.build_bottle? - fi.installed_on_request = args.named.present? - fi.link_keg ||= keg_was_linked if keg_had_linked_opt - if tab - fi.build_bottle ||= tab.built_bottle? - fi.installed_as_dependency = tab.installed_as_dependency - fi.installed_on_request ||= tab.installed_on_request - end + fi = FormulaInstaller.new( + f, + **{ + options: options, + link_keg: keg_had_linked_opt ? keg_was_linked : nil, + installed_as_dependency: tab&.installed_as_dependency, + installed_on_request: args.named.present? || tab&.installed_on_request, + build_bottle: args.build_bottle? || tab&.built_bottle?, + force_bottle: args.force_bottle?, + build_from_source_formulae: args.build_from_source_formulae, + keep_tmp: args.keep_tmp?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose?, + }.compact, + ) upgrade_version = if f.optlinked? "#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" @@ -103,14 +106,12 @@ module Homebrew # We already attempted to upgrade f as part of the dependency tree of # another formula. In that case, don't generate an error, just move on. nil - rescue CannotInstallFormulaError => e + rescue CannotInstallFormulaError, DownloadError => e ofail e rescue BuildError => e e.dump(verbose: args.verbose?) puts Homebrew.failed = true - rescue DownloadError => e - ofail e ensure # restore previous installation state if build failed begin @@ -136,10 +137,10 @@ module Homebrew end end - def check_installed_dependents(args:) + def check_installed_dependents(formulae, args:) return if Homebrew::EnvConfig.no_installed_dependents_check? - installed_formulae = FormulaInstaller.installed.to_a + installed_formulae = args.dry_run? ? formulae : FormulaInstaller.installed.to_a return if installed_formulae.empty? already_broken_dependents = check_broken_dependents(installed_formulae) @@ -241,14 +242,12 @@ module Homebrew # We already attempted to reinstall f as part of the dependency tree of # another formula. In that case, don't generate an error, just move on. nil - rescue CannotInstallFormulaError => e + rescue CannotInstallFormulaError, DownloadError => e ofail e rescue BuildError => e e.dump(verbose: args.verbose?) puts Homebrew.failed = true - rescue DownloadError => e - ofail e end end diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 45f46f3962..a66263ac4e 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -80,6 +80,8 @@ module Homebrew end module Kernel + extend T::Sig + def require?(path) return false if path.nil? @@ -383,6 +385,7 @@ module Kernel trap("INT", std_trap) end + sig { returns(String) } def capture_stderr old = $stderr $stderr = StringIO.new @@ -500,6 +503,7 @@ module Kernel end end + sig { returns(String) } def shell_profile Utils::Shell.profile end diff --git a/Library/Homebrew/utils/analytics.rb b/Library/Homebrew/utils/analytics.rb index 9524db7218..5ae0e106f5 100644 --- a/Library/Homebrew/utils/analytics.rb +++ b/Library/Homebrew/utils/analytics.rb @@ -9,6 +9,8 @@ module Utils # @api private module Analytics class << self + extend T::Sig + include Context def report(type, metadata = {}) @@ -191,6 +193,7 @@ module Utils get_analytics(json, args: args) end + sig { returns(String) } def custom_prefix_label "custom-prefix" end @@ -339,16 +342,19 @@ module Utils format("%.2f", percent: percent) end + sig { returns(String) } def formula_path "formula" end alias generic_formula_path formula_path + sig { returns(String) } def analytics_path "analytics" end alias generic_analytics_path analytics_path + sig { returns(String) } def cask_path "cask" end diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index fff38c4561..99c727cbd1 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -9,6 +9,8 @@ module Utils # @api private module Bottles class << self + extend T::Sig + def tag @tag ||= "#{ENV["HOMEBREW_PROCESSOR"]}_#{ENV["HOMEBREW_SYSTEM"]}".downcase.to_sym end @@ -30,6 +32,7 @@ module Utils bottle_ext && bottle_url_ext && bottle_ext != bottle_url_ext end + sig { returns(Regexp) } def native_regex /(\.#{Regexp.escape(tag.to_s)}\.bottle\.(\d+\.)?tar\.gz)$/o end @@ -93,10 +96,13 @@ module Utils # Collector for bottle specifications. class Collector + extend T::Sig + extend Forwardable def_delegators :@checksums, :keys, :[], :[]=, :key?, :each_key + sig { void } def initialize @checksums = {} end diff --git a/Library/Homebrew/utils/gems.rb b/Library/Homebrew/utils/gems.rb index 866054123f..0985d6de2d 100644 --- a/Library/Homebrew/utils/gems.rb +++ b/Library/Homebrew/utils/gems.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true # Never `require` anything in this file (except English). It needs to be able to @@ -57,7 +57,7 @@ module Homebrew # Add necessary Ruby and Gem binary directories to PATH. gem_bindir ||= Gem.bindir - paths = ENV["PATH"].split(":") + paths = ENV.fetch("PATH").split(":") paths.unshift(gem_bindir) unless paths.include?(gem_bindir) paths.unshift(ruby_bindir) unless paths.include?(ruby_bindir) ENV["PATH"] = paths.compact.join(":") @@ -85,8 +85,8 @@ module Homebrew end def find_in_path(executable) - ENV["PATH"].split(":").find do |path| - File.executable?("#{path}/#{executable}") + ENV.fetch("PATH").split(":").find do |path| + File.executable?(File.join(path, executable)) end end @@ -104,9 +104,9 @@ module Homebrew def install_bundler_gems! install_bundler! - ENV["BUNDLE_GEMFILE"] = "#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/Gemfile" + ENV["BUNDLE_GEMFILE"] = File.join(ENV.fetch("HOMEBREW_LIBRARY"), "Homebrew", "Gemfile") @bundle_installed ||= begin - bundle = "#{find_in_path(:bundle)}/bundle" + bundle = File.join(find_in_path("bundle"), "bundle") bundle_check_output = `#{bundle} check 2>&1` bundle_check_failed = !$CHILD_STATUS.success? diff --git a/Library/Homebrew/utils/gems.rbi b/Library/Homebrew/utils/gems.rbi new file mode 100644 index 0000000000..47c3ced643 --- /dev/null +++ b/Library/Homebrew/utils/gems.rbi @@ -0,0 +1,27 @@ +# typed: strict + +module Homebrew + sig { returns(String) } + def ruby_bindir; end + + sig { returns(String) } + def gem_user_bindir; end + + sig { params(message: String).void } + def ohai_if_defined(message); end + + sig { params(message: String).returns(T.noreturn) } + def odie_if_defined(message); end + + sig { params(name: String, version: T.nilable(String), executable: String, setup_gem_environment: T::Boolean).void } + def install_gem_setup_path!(name, version: nil, executable: name, setup_gem_environment: true); end + + sig { params(executable: String).returns(T.nilable(String)) } + def find_in_path(executable); end + + sig { void } + def install_bundler!; end + + sig { void } + def install_bundler_gems!; end +end diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index 124ba70255..a235b77d74 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -10,6 +10,8 @@ require "utils/shell" # # @api private module GitHub + extend T::Sig + module_function API_URL = "https://api.github.com" @@ -129,6 +131,7 @@ module GitHub end end + sig { returns(Symbol) } def api_credentials_type if Homebrew::EnvConfig.github_api_token :env_token @@ -776,4 +779,9 @@ module GitHub end end end + + def pull_request_labels(user, repo, pr) + pr_data = open_api(url_to("repos", user, repo, "pulls", pr)) + pr_data["labels"].map { |label| label["name"] } + end end diff --git a/Library/Homebrew/utils/github/actions.rb b/Library/Homebrew/utils/github/actions.rb index 3dc7bf6401..8349f5ad3c 100644 --- a/Library/Homebrew/utils/github/actions.rb +++ b/Library/Homebrew/utils/github/actions.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "utils/tty" @@ -8,6 +8,9 @@ module GitHub # # @api private module Actions + extend T::Sig + + sig { params(string: String).returns(String) } def self.escape(string) # See https://github.community/t/set-output-truncates-multiline-strings/16852/3. string.gsub("%", "%25") @@ -17,6 +20,9 @@ module GitHub # Helper class for formatting annotations on GitHub Actions. class Annotation + extend T::Sig + + sig { params(path: T.any(String, Pathname)).returns(T.nilable(Pathname)) } def self.path_relative_to_workspace(path) workspace = Pathname(ENV.fetch("GITHUB_WORKSPACE", Dir.pwd)).realpath path = Pathname(path) @@ -25,6 +31,12 @@ module GitHub path.realpath.relative_path_from(workspace) end + sig do + params( + type: Symbol, message: String, + file: T.nilable(T.any(String, Pathname)), line: T.nilable(Integer), column: T.nilable(Integer) + ).void + end def initialize(type, message, file: nil, line: nil, column: nil) raise ArgumentError, "Unsupported type: #{type.inspect}" unless [:warning, :error].include?(type) @@ -35,18 +47,25 @@ module GitHub @column = Integer(column) if column end + sig { returns(String) } def to_s - file = "file=#{Actions.escape(@file.to_s)}" if @file - line = "line=#{@line}" if @line - column = "col=#{@column}" if @column + metadata = @type.to_s - metadata = [*file, *line, *column].join(",").presence&.prepend(" ") + if @file + metadata << " file=#{Actions.escape(@file.to_s)}" - "::#{@type}#{metadata}::#{Actions.escape(@message)}" + if @line + metadata << ",line=#{@line}" + metadata << ",col=#{@column}" if @column + end + end + + "::#{metadata}::#{Actions.escape(@message)}" end # An annotation is only relevant if the corresponding `file` is relative to # the `GITHUB_WORKSPACE` directory or if no `file` is specified. + sig { returns(T::Boolean) } def relevant? return true if @file.nil? diff --git a/Library/Homebrew/utils/shared_audits.rb b/Library/Homebrew/utils/shared_audits.rb index 742f01f423..b8fdb8c0f6 100644 --- a/Library/Homebrew/utils/shared_audits.rb +++ b/Library/Homebrew/utils/shared_audits.rb @@ -37,6 +37,7 @@ module SharedAudits "extraterm" => :all, "freetube" => :all, "gitless" => "0.8.8", + "haptickey" => :all, "home-assistant" => :all, "lidarr" => :all, "nuclear" => :all, diff --git a/Library/Homebrew/utils/shebang.rb b/Library/Homebrew/utils/shebang.rb index 762ddf5804..edf36e0f0c 100644 --- a/Library/Homebrew/utils/shebang.rb +++ b/Library/Homebrew/utils/shebang.rb @@ -6,14 +6,19 @@ module Utils # # @api private module Shebang + extend T::Sig + module_function # Specification on how to rewrite a given shebang. # # @api private class RewriteInfo + extend T::Sig + attr_reader :regex, :max_length, :replacement + sig { params(regex: Regexp, max_length: Integer, replacement: T.any(String, Pathname)).void } def initialize(regex, max_length, replacement) @regex = regex @max_length = max_length @@ -27,6 +32,7 @@ module Utils # rewrite_shebang detected_python_shebang, bin/"script.py" # # @api public + sig { params(rewrite_info: RewriteInfo, paths: T::Array[T.any(String, Pathname)]).void } def rewrite_shebang(rewrite_info, *paths) paths.each do |f| f = Pathname(f) diff --git a/Library/Homebrew/utils/sorbet.rb b/Library/Homebrew/utils/sorbet.rb index cbc85f5465..2f91f50bb8 100644 --- a/Library/Homebrew/utils/sorbet.rb +++ b/Library/Homebrew/utils/sorbet.rb @@ -1,4 +1,4 @@ -# typed: strict +# typed: true # frozen_string_literal: true if ENV["HOMEBREW_SORBET_RUNTIME"] @@ -7,7 +7,11 @@ if ENV["HOMEBREW_SORBET_RUNTIME"] require "sorbet-runtime" else # Explicitly prevent `sorbet-runtime` from being loaded. - ENV["GEM_SKIP"] = "sorbet-runtime" + def gem(name, *) + raise Gem::LoadError if name == "sorbet-runtime" + + super + end require "sorbet-runtime-stub" end diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index 5dfd238b38..4ef5fe40f1 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -7,15 +7,15 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/concurrent-ruby-1.1.7 $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.8.5/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.14.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thread_safe-0.3.6/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-1.2.7/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.4.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-1.2.8/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.0.3.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.8/lib" $:.unshift "#{path}/" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/byebug-11.1.3" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/byebug-11.1.3" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/json-2.3.1" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/json-2.3.1" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/json-2.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/docile-1.3.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib" @@ -27,20 +27,20 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/highline-2.0.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/commander-4.5.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/connection_pool-2.2.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.4.4/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/unf_ext-0.0.7.7" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/unf_ext-0.0.7.7" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf_ext-0.0.7.7/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf-0.1.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/domain_name-0.5.20190701/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/elftools-1.1.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/hpricot-0.8.6" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/hpricot-0.8.6" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/hpricot-0.8.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/http-cookie-1.0.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-data-3.2020.0512/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-data-3.2020.1104/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-3.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-digest_auth-1.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-4.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.4.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/nokogiri-1.10.10" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/nokogiri-1.10.10" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.10.10/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ntlm-http-0.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" @@ -51,12 +51,12 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6036/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6076/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/pry-0.13.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/rdiscount-2.2.0.2" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/rdiscount-2.2.0.2" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rdiscount-2.2.0.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/regexp_parser-1.8.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rexml-3.2.4/lib" @@ -72,13 +72,13 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.2.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.8.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.3.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.9.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.5.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6036-universal-darwin-19/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6036/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.5.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6076-universal-darwin-20/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6076/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-stub-0.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/spoom-1.0.4/lib" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/sum.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/sum.rb deleted file mode 100644 index 0adc195db0..0000000000 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/sum.rb +++ /dev/null @@ -1,134 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module Cop - module Performance - # This cop identifies places where custom code finding the sum of elements - # in some Enumerable object can be replaced by `Enumerable#sum` method. - # - # @example - # # bad - # [1, 2, 3].inject(:+) - # [1, 2, 3].reduce(10, :+) - # [1, 2, 3].inject(&:+) - # [1, 2, 3].reduce { |acc, elem| acc + elem } - # - # # good - # [1, 2, 3].sum - # [1, 2, 3].sum(10) - # [1, 2, 3].sum - # - class Sum < Base - include RangeHelp - extend AutoCorrector - - MSG = 'Use `%s` instead of `%s`.' - - def_node_matcher :sum_candidate?, <<~PATTERN - (send _ ${:inject :reduce} $_init ? ${(sym :+) (block_pass (sym :+))}) - PATTERN - - def_node_matcher :sum_with_block_candidate?, <<~PATTERN - (block - $(send _ {:inject :reduce} $_init ?) - (args (arg $_acc) (arg $_elem)) - $send) - PATTERN - - def_node_matcher :acc_plus_elem?, <<~PATTERN - (send (lvar %1) :+ (lvar %2)) - PATTERN - alias elem_plus_acc? acc_plus_elem? - - def on_send(node) - sum_candidate?(node) do |method, init, operation| - range = sum_method_range(node) - message = build_method_message(method, init, operation) - - add_offense(range, message: message) do |corrector| - autocorrect(corrector, init, range) - end - end - end - - def on_block(node) - sum_with_block_candidate?(node) do |send, init, var_acc, var_elem, body| - if acc_plus_elem?(body, var_acc, var_elem) || elem_plus_acc?(body, var_elem, var_acc) - range = sum_block_range(send, node) - message = build_block_message(send, init, var_acc, var_elem, body) - - add_offense(range, message: message) do |corrector| - autocorrect(corrector, init, range) - end - end - end - end - - private - - def autocorrect(corrector, init, range) - return if init.empty? - - replacement = build_good_method(init) - - corrector.replace(range, replacement) - end - - def sum_method_range(node) - range_between(node.loc.selector.begin_pos, node.loc.end.end_pos) - end - - def sum_block_range(send, node) - range_between(send.loc.selector.begin_pos, node.loc.end.end_pos) - end - - def build_method_message(method, init, operation) - good_method = build_good_method(init) - bad_method = build_method_bad_method(init, method, operation) - format(MSG, good_method: good_method, bad_method: bad_method) - end - - def build_block_message(send, init, var_acc, var_elem, body) - good_method = build_good_method(init) - bad_method = build_block_bad_method(send.method_name, init, var_acc, var_elem, body) - format(MSG, good_method: good_method, bad_method: bad_method) - end - - def build_good_method(init) - good_method = 'sum' - - unless init.empty? - init = init.first - good_method += "(#{init.source})" unless init.int_type? && init.value.zero? - end - good_method - end - - def build_method_bad_method(init, method, operation) - bad_method = "#{method}(" - unless init.empty? - init = init.first - bad_method += "#{init.source}, " - end - bad_method += if operation.block_pass_type? - '&:+)' - else - ':+)' - end - bad_method - end - - def build_block_bad_method(method, init, var_acc, var_elem, body) - bad_method = method.to_s - - unless init.empty? - init = init.first - bad_method += "(#{init.source})" - end - bad_method += " { |#{var_acc}, #{var_elem}| #{body.source} }" - bad_method - end - end - end - end -end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance/version.rb deleted file mode 100644 index 3e176f814d..0000000000 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance/version.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module Performance - module Version - STRING = '1.8.1' - end - end -end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/config/default.yml b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/config/default.yml similarity index 92% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/config/default.yml rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/config/default.yml index 6a33802fbf..547c610846 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/config/default.yml +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/config/default.yml @@ -7,6 +7,11 @@ Performance/AncestorsInclude: Safe: false VersionAdded: '1.7' +Performance/ArraySemiInfiniteRangeSlice: + Description: 'Identifies places where slicing arrays with semi-infinite ranges can be replaced by `Array#take` and `Array#drop`.' + Enabled: pending + VersionAdded: '1.9' + Performance/BigDecimalWithNumericArgument: Description: 'Convert numeric argument to string before passing to BigDecimal.' Enabled: 'pending' @@ -17,11 +22,17 @@ Performance/BindCall: Enabled: true VersionAdded: '1.6' +Performance/BlockGivenWithExplicitBlock: + Description: 'Check block argument explicitly instead of using `block_given?`.' + Enabled: pending + VersionAdded: '1.9' + Performance/Caller: Description: >- Use `caller(n..n)` instead of `caller`. Enabled: true VersionAdded: '0.49' + VersionChanged: '1.9' Performance/CaseWhenSplat: Description: >- @@ -51,7 +62,7 @@ Performance/ChainArrayAllocation: Performance/CollectionLiteralInLoop: Description: 'Extract Array and Hash literals outside of loops into local variables or constants.' - Enabled: true + Enabled: 'pending' VersionAdded: '1.8' # Min number of elements to consider an offense MinSize: 1 @@ -61,6 +72,11 @@ Performance/CompareWithBlock: Enabled: true VersionAdded: '0.46' +Performance/ConstantRegexp: + Description: 'Finds regular expressions with dynamic components that are all constants.' + Enabled: pending + VersionAdded: '1.9' + Performance/Count: Description: >- Use `count` instead of `{select,find_all,filter,reject}...{size,count,length}`. @@ -154,6 +170,12 @@ Performance/IoReadlines: Enabled: false VersionAdded: '1.7' +Performance/MethodObjectAsBlock: + Description: 'Use block explicitly instead of block-passing a method object.' + Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code' + Enabled: pending + VersionAdded: '1.9' + Performance/OpenStruct: Description: 'Use `Struct` instead of `OpenStruct`.' Enabled: false @@ -283,7 +305,9 @@ Performance/TimesMap: Performance/UnfreezeString: Description: 'Use unary plus to get an unfrozen string literal.' Enabled: true + SafeAutoCorrect: false VersionAdded: '0.50' + VersionChanged: '1.9' Performance/UriDefaultParser: Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop-performance.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop-performance.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop-performance.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop-performance.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/mixin/regexp_metacharacter.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/mixin/regexp_metacharacter.rb similarity index 90% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/mixin/regexp_metacharacter.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/mixin/regexp_metacharacter.rb index 9d3ab3cc43..db41b0af87 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/mixin/regexp_metacharacter.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/mixin/regexp_metacharacter.rb @@ -25,7 +25,7 @@ module RuboCop # (tricky: \s, \d, and so on are metacharacters, but other characters # escaped with a slash are just literals. LITERAL_REGEX takes all # that into account.) - /\A\\A(?:#{Util::LITERAL_REGEX})+\z/.match?(regex_str) + /\A\\A(?:#{Util::LITERAL_REGEX})+\z/o.match?(regex_str) end def literal_at_start_with_caret?(regex_str) @@ -35,21 +35,21 @@ module RuboCop # (tricky: \s, \d, and so on are metacharacters, but other characters # escaped with a slash are just literals. LITERAL_REGEX takes all # that into account.) - /\A\^(?:#{Util::LITERAL_REGEX})+\z/.match?(regex_str) + /\A\^(?:#{Util::LITERAL_REGEX})+\z/o.match?(regex_str) end def literal_at_end_with_backslash_z?(regex_str) # is this regexp 'literal' in the sense of only matching literal # chars, rather than using metachars like . and * and so on? # also, is it anchored at the end of the string? - /\A(?:#{Util::LITERAL_REGEX})+\\z\z/.match?(regex_str) + /\A(?:#{Util::LITERAL_REGEX})+\\z\z/o.match?(regex_str) end def literal_at_end_with_dollar?(regex_str) # is this regexp 'literal' in the sense of only matching literal # chars, rather than using metachars like . and * and so on? # also, is it anchored at the end of the string? - /\A(?:#{Util::LITERAL_REGEX})+\$\z/.match?(regex_str) + /\A(?:#{Util::LITERAL_REGEX})+\$\z/o.match?(regex_str) end def drop_start_metacharacter(regexp_string) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/mixin/sort_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/mixin/sort_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/mixin/sort_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/mixin/sort_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/ancestors_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/ancestors_include.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/ancestors_include.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/ancestors_include.rb index 62ae0cd19c..b1e9109983 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/ancestors_include.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/ancestors_include.rb @@ -18,6 +18,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `<=` instead of `ancestors.include?`.' + RESTRICT_ON_SEND = %i[include?].freeze def_node_matcher :ancestors_include_candidate?, <<~PATTERN (send (send $_subclass :ancestors) :include? $_superclass) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb new file mode 100644 index 0000000000..dffe677c55 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Performance + # This cop identifies places where slicing arrays with semi-infinite ranges + # can be replaced by `Array#take` and `Array#drop`. + # + # @example + # # bad + # # array[..2] + # # array[...2] + # # array[2..] + # # array[2...] + # # array.slice(..2) + # + # # good + # array.take(3) + # array.take(2) + # array.drop(2) + # array.drop(2) + # array.take(3) + # + class ArraySemiInfiniteRangeSlice < Base + include RangeHelp + extend AutoCorrector + extend TargetRubyVersion + + minimum_target_ruby_version 2.7 + + MSG = 'Use `%s` instead of `%s` with semi-infinite range.' + + SLICE_METHODS = Set[:[], :slice].freeze + RESTRICT_ON_SEND = SLICE_METHODS + + def_node_matcher :endless_range_slice?, <<~PATTERN + (send $_ $%SLICE_METHODS $#endless_range?) + PATTERN + + def_node_matcher :endless_range?, <<~PATTERN + { + ({irange erange} nil? (int positive?)) + ({irange erange} (int positive?) nil?) + } + PATTERN + + def on_send(node) + endless_range_slice?(node) do |receiver, method_name, range_node| + prefer = range_node.begin ? :drop : :take + message = format(MSG, prefer: prefer, current: method_name) + + add_offense(node, message: message) do |corrector| + corrector.replace(node, correction(receiver, range_node)) + end + end + end + + private + + def correction(receiver, range_node) + method_call = if range_node.begin + "drop(#{range_node.begin.value})" + elsif range_node.irange_type? + "take(#{range_node.end.value + 1})" + else + "take(#{range_node.end.value})" + end + + "#{receiver.source}.#{method_call}" + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb index 87bea01028..1248544cf2 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb @@ -20,6 +20,7 @@ module RuboCop extend AutoCorrector MSG = 'Convert numeric argument to string before passing to `BigDecimal`.' + RESTRICT_ON_SEND = %i[BigDecimal].freeze def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN (send nil? :BigDecimal $numeric_type? ...) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/bind_call.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/bind_call.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/bind_call.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/bind_call.rb index e143987762..001209171f 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/bind_call.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/bind_call.rb @@ -28,6 +28,7 @@ module RuboCop MSG = 'Use `bind_call(%s%s%s)` ' \ 'instead of `bind(%s).call(%s)`.' + RESTRICT_ON_SEND = %i[call].freeze def_node_matcher :bind_with_call_method?, <<~PATTERN (send diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/block_given_with_explicit_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/block_given_with_explicit_block.rb new file mode 100644 index 0000000000..a25ac1988b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/block_given_with_explicit_block.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Performance + # This cop identifies unnecessary use of a `block_given?` where explicit check + # of block argument would suffice. + # + # @example + # # bad + # def method(&block) + # do_something if block_given? + # end + # + # # good + # def method(&block) + # do_something if block + # end + # + # # good - block is reassigned + # def method(&block) + # block ||= -> { do_something } + # warn "Using default ..." unless block_given? + # # ... + # end + # + class BlockGivenWithExplicitBlock < Base + extend AutoCorrector + + RESTRICT_ON_SEND = %i[block_given?].freeze + MSG = 'Check block argument explicitly instead of using `block_given?`.' + + def_node_matcher :reassigns_block_arg?, '`(lvasgn %1 ...)' + + def on_send(node) + def_node = node.each_ancestor(:def, :defs).first + return unless def_node + + block_arg = def_node.arguments.find(&:blockarg_type?) + return unless block_arg + + block_arg_name = block_arg.loc.name.source.to_sym + return if reassigns_block_arg?(def_node, block_arg_name) + + add_offense(node) do |corrector| + corrector.replace(node, block_arg_name) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/caller.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/caller.rb similarity index 74% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/caller.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/caller.rb index fc8077cd7f..a071c04b8c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/caller.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/caller.rb @@ -19,10 +19,10 @@ module RuboCop # caller_locations(2..2).first # caller_locations(1..1).first class Caller < Base - MSG_BRACE = 'Use `%s(%d..%d).first`' \ - ' instead of `%s[%d]`.' - MSG_FIRST = 'Use `%s(%d..%d).first`' \ - ' instead of `%s.first`.' + extend AutoCorrector + + MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[first []].freeze def_node_matcher :slow_caller?, <<~PATTERN { @@ -41,26 +41,24 @@ module RuboCop def on_send(node) return unless caller_with_scope_method?(node) - message = message(node) - add_offense(node, message: message) - end - - private - - def message(node) method_name = node.receiver.method_name caller_arg = node.receiver.first_argument n = caller_arg ? int_value(caller_arg) : 1 - if node.method?(:[]) m = int_value(node.first_argument) n += m - format(MSG_BRACE, n: n, m: m, method: method_name) - else - format(MSG_FIRST, n: n, method: method_name) + end + + preferred_method = "#{method_name}(#{n}..#{n}).first" + + message = format(MSG, preferred_method: preferred_method, current_method: node.source) + add_offense(node, message: message) do |corrector| + corrector.replace(node, preferred_method) end end + private + def int_value(node) node.children[0] end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/case_when_splat.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/case_when_splat.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/case_when_splat.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/case_when_splat.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/casecmp.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/casecmp.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/casecmp.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/casecmp.rb index 0bccda3d84..c981757c79 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/casecmp.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/casecmp.rb @@ -23,6 +23,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[== eql? !=].freeze CASE_METHODS = %i[downcase upcase].freeze def_node_matcher :downcase_eq, <<~PATTERN diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/chain_array_allocation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/chain_array_allocation.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/chain_array_allocation.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/chain_array_allocation.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/collection_literal_in_loop.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/collection_literal_in_loop.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/collection_literal_in_loop.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/collection_literal_in_loop.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/compare_with_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/compare_with_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/compare_with_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/compare_with_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/constant_regexp.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/constant_regexp.rb new file mode 100644 index 0000000000..09e5c0d81f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/constant_regexp.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Performance + # This cop finds regular expressions with dynamic components that are all constants. + # + # Ruby allocates a new Regexp object every time it executes a code containing such + # a regular expression. It is more efficient to extract it into a constant + # or add an `/o` option to perform `#{}` interpolation only once and reuse that + # Regexp object. + # + # @example + # + # # bad + # def tokens(pattern) + # pattern.scan(TOKEN).reject { |token| token.match?(/\A#{SEPARATORS}\Z/) } + # end + # + # # good + # ALL_SEPARATORS = /\A#{SEPARATORS}\Z/ + # def tokens(pattern) + # pattern.scan(TOKEN).reject { |token| token.match?(ALL_SEPARATORS) } + # end + # + # # good + # def tokens(pattern) + # pattern.scan(TOKEN).reject { |token| token.match?(/\A#{SEPARATORS}\Z/o) } + # end + # + class ConstantRegexp < Base + extend AutoCorrector + + MSG = 'Extract this regexp into a constant or append an `/o` option to its options.' + + def on_regexp(node) + return if within_const_assignment?(node) || + !include_interpolated_const?(node) || + node.single_interpolation? + + add_offense(node) do |corrector| + corrector.insert_after(node, 'o') + end + end + + private + + def within_const_assignment?(node) + node.each_ancestor(:casgn).any? + end + + def_node_matcher :regexp_escape?, <<~PATTERN + (send + (const nil? :Regexp) :escape const_type?) + PATTERN + + def include_interpolated_const?(node) + return false unless node.interpolation? + + node.each_child_node(:begin).all? do |begin_node| + inner_node = begin_node.children.first + inner_node && (inner_node.const_type? || regexp_escape?(inner_node)) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/count.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/count.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/count.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/count.rb index 0b20aa2141..d6c6ad0501 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/count.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/count.rb @@ -42,6 +42,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `count` instead of `%s...%s`.' + RESTRICT_ON_SEND = %i[count length size].freeze def_node_matcher :count_candidate?, <<~PATTERN { diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/delete_prefix.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/delete_prefix.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/delete_prefix.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/delete_prefix.rb index 9ec14b62d1..f023ffbc20 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/delete_prefix.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/delete_prefix.rb @@ -51,6 +51,7 @@ module RuboCop minimum_target_ruby_version 2.5 MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze PREFERRED_METHODS = { gsub: :delete_prefix, diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/delete_suffix.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/delete_suffix.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/delete_suffix.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/delete_suffix.rb index 45f8c06004..d4251210bd 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/delete_suffix.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/delete_suffix.rb @@ -51,6 +51,7 @@ module RuboCop minimum_target_ruby_version 2.5 MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze PREFERRED_METHODS = { gsub: :delete_suffix, diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/detect.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/detect.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/detect.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/detect.rb index 96fe8dbd81..f250ff64ae 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/detect.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/detect.rb @@ -4,8 +4,8 @@ module RuboCop module Cop module Performance # This cop is used to identify usages of `first`, `last`, `[0]` or `[-1]` - # chained to `select`, `find_all`, or `find_all` - # and change them to use `detect` instead. + # chained to `select`, `find_all` or `filter` and change them to use + # `detect` instead. # # @example # # bad @@ -39,6 +39,7 @@ module RuboCop '`%s[%i]`.' INDEX_REVERSE_MSG = 'Use `reverse.%s` instead of ' \ '`%s[%i]`.' + RESTRICT_ON_SEND = %i[first last []].freeze def_node_matcher :detect_candidate?, <<~PATTERN { diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/double_start_end_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/double_start_end_with.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/double_start_end_with.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/double_start_end_with.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/end_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/end_with.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/end_with.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/end_with.rb index 26545ecc1b..155c48f8a2 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/end_with.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/end_with.rb @@ -47,6 +47,7 @@ module RuboCop MSG = 'Use `String#end_with?` instead of a regex match anchored to ' \ 'the end of the string.' + RESTRICT_ON_SEND = %i[match =~ match?].freeze def_node_matcher :redundant_regex?, <<~PATTERN {(send $!nil? {:match :=~ :match?} (regexp (str $#literal_at_end?) (regopt))) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/fixed_size.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/fixed_size.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/fixed_size.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/fixed_size.rb index 9469a2bb89..01959f2130 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/fixed_size.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/fixed_size.rb @@ -47,6 +47,7 @@ module RuboCop # class FixedSize < Base MSG = 'Do not compute the size of statically sized objects.' + RESTRICT_ON_SEND = %i[count length size].freeze def_node_matcher :counter, <<~MATCHER (send ${array hash str sym} {:count :length :size} $...) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/flat_map.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/flat_map.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/flat_map.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/flat_map.rb index 6179a8838b..150e9c841a 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/flat_map.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/flat_map.rb @@ -19,6 +19,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `flat_map` instead of `%s...%s`.' + RESTRICT_ON_SEND = %i[flatten flatten!].freeze FLATTEN_MULTIPLE_LEVELS = ' Beware, `flat_map` only flattens 1 level ' \ 'and `flatten` can be used to flatten ' \ 'multiple levels.' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/inefficient_hash_search.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/inefficient_hash_search.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/inefficient_hash_search.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/inefficient_hash_search.rb index 60ff196cbe..a5c47def6c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/inefficient_hash_search.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/inefficient_hash_search.rb @@ -39,6 +39,8 @@ module RuboCop class InefficientHashSearch < Base extend AutoCorrector + RESTRICT_ON_SEND = %i[include?].freeze + def_node_matcher :inefficient_include?, <<~PATTERN (send (send $_ {:keys :values}) :include? _) PATTERN diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/io_readlines.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/io_readlines.rb similarity index 92% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/io_readlines.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/io_readlines.rb index 1290a9b84c..fb9d04b034 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/io_readlines.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/io_readlines.rb @@ -29,14 +29,14 @@ module RuboCop extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' - ENUMERABLE_METHODS = (Enumerable.instance_methods + [:each]).freeze + RESTRICT_ON_SEND = (Enumerable.instance_methods + [:each]).freeze def_node_matcher :readlines_on_class?, <<~PATTERN - $(send $(send (const nil? {:IO :File}) :readlines ...) #enumerable_method?) + $(send $(send (const nil? {:IO :File}) :readlines ...) _) PATTERN def_node_matcher :readlines_on_instance?, <<~PATTERN - $(send $(send ${nil? !const_type?} :readlines ...) #enumerable_method? ...) + $(send $(send ${nil? !const_type?} :readlines ...) _ ...) PATTERN def on_send(node) @@ -55,10 +55,6 @@ module RuboCop private - def enumerable_method?(node) - ENUMERABLE_METHODS.include?(node.to_sym) - end - def autocorrect(corrector, enumerable_call, readlines_call, receiver) # We cannot safely correct `.readlines` method called on IO/File classes # due to its signature and we are not sure with implicit receiver diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/method_object_as_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/method_object_as_block.rb new file mode 100644 index 0000000000..796ea10a10 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/method_object_as_block.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Performance + # This cop identifies places where methods are converted to blocks, with the + # use of `&method`, and passed as arguments to method calls. + # It is faster to replace those with explicit blocks, calling those methods inside. + # + # @example + # # bad + # array.map(&method(:do_something)) + # [1, 2, 3].each(&out.method(:puts)) + # + # # good + # array.map { |x| do_something(x) } + # [1, 2, 3].each { |x| out.puts(x) } + # + class MethodObjectAsBlock < Base + MSG = 'Use block explicitly instead of block-passing a method object.' + + def_node_matcher :method_object_as_argument?, <<~PATTERN + (^send (send _ :method sym)) + PATTERN + + def on_block_pass(node) + add_offense(node) if method_object_as_argument?(node) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/open_struct.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/open_struct.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/open_struct.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/open_struct.rb index 25ad5f8f63..6709b68e14 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/open_struct.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/open_struct.rb @@ -30,6 +30,7 @@ module RuboCop class OpenStruct < Base MSG = 'Consider using `Struct` over `OpenStruct` ' \ 'to optimize the performance.' + RESTRICT_ON_SEND = %i[new].freeze def_node_matcher :open_struct, <<~PATTERN (send (const {nil? cbase} :OpenStruct) :new ...) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/range_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/range_include.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/range_include.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/range_include.rb index e32d9e42cd..e39dcc2400 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/range_include.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/range_include.rb @@ -28,6 +28,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `Range#cover?` instead of `Range#%s`.' + RESTRICT_ON_SEND = %i[include? member?].freeze # TODO: If we traced out assignments of variables to their uses, we # might pick up on a few more instances of this issue diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_block_call.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_block_call.rb similarity index 94% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_block_call.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_block_call.rb index 44b9d493bd..e80d4d5f6e 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_block_call.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_block_call.rb @@ -80,11 +80,11 @@ module RuboCop def calls_to_report(argname, body) return [] if blockarg_assigned?(body, argname) - calls = to_enum(:blockarg_calls, body, argname) + blockarg_calls(body, argname).map do |call| + return [] if args_include_block_pass?(call) - return [] if calls.any? { |call| args_include_block_pass?(call) } - - calls + call + end end def args_include_block_pass?(blockcall) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_match.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_match.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_match.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_match.rb index 791bcebf71..b75a8f856c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_match.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_match.rb @@ -22,6 +22,7 @@ module RuboCop MSG = 'Use `=~` in places where the `MatchData` returned by ' \ '`#match` will not be used.' + RESTRICT_ON_SEND = %i[match].freeze # 'match' is a fairly generic name, so we don't flag it unless we see # a string or regexp literal on one side or the other diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_merge.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_merge.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_merge.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_merge.rb index 244e768199..d986cc3a09 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_merge.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_merge.rb @@ -29,6 +29,7 @@ module RuboCop AREF_ASGN = '%s[%s] = %s' MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[merge!].freeze WITH_MODIFIER_CORRECTION = <<~RUBY %s %s diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_sort_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_sort_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_sort_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_sort_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_string_chars.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_string_chars.rb similarity index 92% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_string_chars.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_string_chars.rb index be84d464c4..9d5eb625c6 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/redundant_string_chars.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/redundant_string_chars.rb @@ -44,10 +44,10 @@ module RuboCop extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' - REPLACEABLE_METHODS = %i[[] slice first last take drop length size empty?].freeze + RESTRICT_ON_SEND = %i[[] slice first last take drop length size empty?].freeze def_node_matcher :redundant_chars_call?, <<~PATTERN - (send $(send _ :chars) $#replaceable_method? $...) + (send $(send _ :chars) $_ $...) PATTERN def on_send(node) @@ -66,10 +66,6 @@ module RuboCop private - def replaceable_method?(method_name) - REPLACEABLE_METHODS.include?(method_name) - end - def offense_range(receiver, node) range_between(receiver.loc.selector.begin_pos, node.loc.expression.end_pos) end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/regexp_match.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/regexp_match.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/regexp_match.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/regexp_match.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/reverse_each.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/reverse_each.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/reverse_each.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/reverse_each.rb index 86041cd6be..51fc4d05e0 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/reverse_each.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/reverse_each.rb @@ -17,6 +17,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `reverse_each` instead of `reverse.each`.' + RESTRICT_ON_SEND = %i[each].freeze UNDERSCORE = '_' def_node_matcher :reverse_each?, <<~MATCHER diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/reverse_first.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/reverse_first.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/reverse_first.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/reverse_first.rb index 13d627fe4c..7db7f53e09 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/reverse_first.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/reverse_first.rb @@ -21,6 +21,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[first].freeze def_node_matcher :reverse_first_candidate?, <<~PATTERN (send $(send _ :reverse) :first (int _)?) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/size.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/size.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/size.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/size.rb index b67c544dc8..4356c5d6e5 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/size.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/size.rb @@ -39,6 +39,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `size` instead of `count`.' + RESTRICT_ON_SEND = %i[count].freeze def_node_matcher :array?, <<~PATTERN { diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/sort_reverse.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/sort_reverse.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/sort_reverse.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/sort_reverse.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/squeeze.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/squeeze.rb similarity index 94% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/squeeze.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/squeeze.rb index 39fa4fb323..315e5e3a23 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/squeeze.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/squeeze.rb @@ -22,6 +22,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[gsub gsub!].freeze PREFERRED_METHODS = { gsub: :squeeze, @@ -58,7 +59,7 @@ module RuboCop private def repeating_literal?(regex_str) - regex_str.match?(/\A(?:#{Util::LITERAL_REGEX})\+\z/) + regex_str.match?(/\A(?:#{Util::LITERAL_REGEX})\+\z/o) end end end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/start_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/start_with.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/start_with.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/start_with.rb index b343247134..c55ac7af5c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/start_with.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/start_with.rb @@ -47,6 +47,7 @@ module RuboCop MSG = 'Use `String#start_with?` instead of a regex match anchored to ' \ 'the beginning of the string.' + RESTRICT_ON_SEND = %i[match =~ match?].freeze def_node_matcher :redundant_regex?, <<~PATTERN {(send $!nil? {:match :=~ :match?} (regexp (str $#literal_at_start?) (regopt))) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/string_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/string_include.rb similarity index 93% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/string_include.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/string_include.rb index 655023535e..c549300aff 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/string_include.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/string_include.rb @@ -23,6 +23,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `String#include?` instead of a regex match with literal-only pattern.' + RESTRICT_ON_SEND = %i[match =~ match?].freeze def_node_matcher :redundant_regex?, <<~PATTERN {(send $!nil? {:match :=~ :match?} (regexp (str $#literal?) (regopt))) @@ -47,7 +48,7 @@ module RuboCop private def literal?(regex_str) - regex_str.match?(/\A#{Util::LITERAL_REGEX}+\z/) + regex_str.match?(/\A#{Util::LITERAL_REGEX}+\z/o) end end end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/string_replacement.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/string_replacement.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/string_replacement.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/string_replacement.rb index 6364f98ab8..68f85eab4f 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/string_replacement.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/string_replacement.rb @@ -23,6 +23,7 @@ module RuboCop extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' + RESTRICT_ON_SEND = %i[gsub gsub!].freeze DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/.freeze DELETE = 'delete' TR = 'tr' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/sum.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/sum.rb new file mode 100644 index 0000000000..211b17425c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/sum.rb @@ -0,0 +1,236 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Performance + # This cop identifies places where custom code finding the sum of elements + # in some Enumerable object can be replaced by `Enumerable#sum` method. + # + # This cop can change auto-correction scope depending on the value of + # `SafeAutoCorrect`. + # Its auto-correction is marked as safe by default (`SafeAutoCorrect: true`) + # to prevent `TypeError` in auto-correced code when initial value is not + # specified as shown below: + # + # [source,ruby] + # ---- + # ['a', 'b'].sum # => (String can't be coerced into Integer) + # ---- + # + # Therefore if initial value is not specified, unsafe auto-corrected will not occur. + # + # If you always want to enable auto-correction, you can set `SafeAutoCorrect: false`. + # + # [source,yaml] + # ---- + # Performance/Sum: + # SafeAutoCorrect: false + # ---- + # + # Please note that the auto-correction command line option will be changed from + # `rubocop -a` to `rubocop -A`, which includes unsafe auto-correction. + # + # @example + # # bad + # [1, 2, 3].inject(:+) # These bad cases with no initial value are unsafe and + # [1, 2, 3].inject(&:+) # will not be auto-correced by default. If you want to + # [1, 2, 3].reduce { |acc, elem| acc + elem } # auto-corrected, you can set `SafeAutoCorrect: false`. + # [1, 2, 3].reduce(10, :+) + # [1, 2, 3].map { |elem| elem ** 2 }.sum + # [1, 2, 3].collect(&:count).sum(10) + # + # # good + # [1, 2, 3].sum + # [1, 2, 3].sum(10) + # [1, 2, 3].sum { |elem| elem ** 2 } + # [1, 2, 3].sum(10, &:count) + # + class Sum < Base + include RangeHelp + extend AutoCorrector + + MSG = 'Use `%s` instead of `%s`.' + MSG_IF_NO_INIT_VALUE = + 'Use `%s` instead of `%s`, unless calling `%s` on an empty array.' + RESTRICT_ON_SEND = %i[inject reduce sum].freeze + + def_node_matcher :sum_candidate?, <<~PATTERN + (send _ ${:inject :reduce} $_init ? ${(sym :+) (block_pass (sym :+))}) + PATTERN + + def_node_matcher :sum_map_candidate?, <<~PATTERN + (send + { + (block $(send _ {:map :collect}) ...) + $(send _ {:map :collect} (block_pass _)) + } + :sum $_init ?) + PATTERN + + def_node_matcher :sum_with_block_candidate?, <<~PATTERN + (block + $(send _ {:inject :reduce} $_init ?) + (args (arg $_acc) (arg $_elem)) + $send) + PATTERN + + def_node_matcher :acc_plus_elem?, <<~PATTERN + (send (lvar %1) :+ (lvar %2)) + PATTERN + alias elem_plus_acc? acc_plus_elem? + + def on_send(node) + return if empty_array_literal?(node) + + handle_sum_candidate(node) + handle_sum_map_candidate(node) + end + + def on_block(node) + sum_with_block_candidate?(node) do |send, init, var_acc, var_elem, body| + if acc_plus_elem?(body, var_acc, var_elem) || elem_plus_acc?(body, var_elem, var_acc) + range = sum_block_range(send, node) + message = build_block_message(send, init, var_acc, var_elem, body) + + add_offense(range, message: message) do |corrector| + autocorrect(corrector, init, range) + end + end + end + end + + private + + def handle_sum_candidate(node) + sum_candidate?(node) do |method, init, operation| + range = sum_method_range(node) + message = build_method_message(node, method, init, operation) + + add_offense(range, message: message) do |corrector| + autocorrect(corrector, init, range) + end + end + end + + def handle_sum_map_candidate(node) + sum_map_candidate?(node) do |map, init| + next if node.block_literal? || node.block_argument? + + message = build_sum_map_message(map.method_name, init) + + add_offense(sum_map_range(map, node), message: message) do |corrector| + autocorrect_sum_map(corrector, node, map, init) + end + end + end + + def empty_array_literal?(node) + receiver = node.children.first + array_literal?(node) && receiver && receiver.children.empty? + end + + def array_literal?(node) + receiver = node.children.first + receiver&.literal? && receiver&.array_type? + end + + def autocorrect(corrector, init, range) + return if init.empty? && safe_autocorrect? + + replacement = build_good_method(init) + + corrector.replace(range, replacement) + end + + def autocorrect_sum_map(corrector, sum, map, init) + sum_range = method_call_with_args_range(sum) + map_range = method_call_with_args_range(map) + + block_pass = map.last_argument if map.last_argument&.block_pass_type? + replacement = build_good_method(init, block_pass) + + corrector.remove(sum_range) + corrector.replace(map_range, ".#{replacement}") + end + + def sum_method_range(node) + range_between(node.loc.selector.begin_pos, node.loc.end.end_pos) + end + + def sum_map_range(map, sum) + range_between(map.loc.selector.begin_pos, sum.source_range.end.end_pos) + end + + def sum_block_range(send, node) + range_between(send.loc.selector.begin_pos, node.loc.end.end_pos) + end + + def build_method_message(node, method, init, operation) + good_method = build_good_method(init) + bad_method = build_method_bad_method(init, method, operation) + msg = if init.empty? && !array_literal?(node) + MSG_IF_NO_INIT_VALUE + else + MSG + end + format(msg, good_method: good_method, bad_method: bad_method) + end + + def build_sum_map_message(method, init) + sum_method = build_good_method(init) + good_method = "#{sum_method} { ... }" + bad_method = "#{method} { ... }.#{sum_method}" + format(MSG, good_method: good_method, bad_method: bad_method) + end + + def build_block_message(send, init, var_acc, var_elem, body) + good_method = build_good_method(init) + bad_method = build_block_bad_method(send.method_name, init, var_acc, var_elem, body) + format(MSG, good_method: good_method, bad_method: bad_method) + end + + def build_good_method(init, block_pass = nil) + good_method = 'sum' + + args = [] + unless init.empty? + init = init.first + args << init.source unless init.int_type? && init.value.zero? + end + args << block_pass.source if block_pass + good_method += "(#{args.join(', ')})" unless args.empty? + good_method + end + + def build_method_bad_method(init, method, operation) + bad_method = "#{method}(" + unless init.empty? + init = init.first + bad_method += "#{init.source}, " + end + bad_method += if operation.block_pass_type? + '&:+)' + else + ':+)' + end + bad_method + end + + def build_block_bad_method(method, init, var_acc, var_elem, body) + bad_method = method.to_s + + unless init.empty? + init = init.first + bad_method += "(#{init.source})" + end + bad_method += " { |#{var_acc}, #{var_elem}| #{body.source} }" + bad_method + end + + def method_call_with_args_range(node) + node.receiver.source_range.end.join(node.source_range.end) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/times_map.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/times_map.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/times_map.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/times_map.rb index 8718de9f96..907983a04c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/times_map.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/times_map.rb @@ -23,6 +23,7 @@ module RuboCop MESSAGE = 'Use `Array.new(%s)` with a block ' \ 'instead of `.times.%s`' MESSAGE_ONLY_IF = 'only if `%s` is always 0 or more' + RESTRICT_ON_SEND = %i[map collect].freeze def on_send(node) check(node) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/unfreeze_string.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/unfreeze_string.rb similarity index 69% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/unfreeze_string.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/unfreeze_string.rb index e366cec098..2a820bee87 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/unfreeze_string.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/unfreeze_string.rb @@ -10,6 +10,7 @@ module RuboCop # NOTE: `String.new` (without operator) is not exactly the same as `+''`. # These differ in encoding. `String.new.encoding` is always `ASCII-8BIT`. # However, `(+'').encoding` is the same as script encoding(e.g. `UTF-8`). + # Therefore, auto-correction is unsafe. # So, if you expect `ASCII-8BIT` encoding, disable this cop. # # @example @@ -24,7 +25,10 @@ module RuboCop # +'something' # +'' class UnfreezeString < Base + extend AutoCorrector + MSG = 'Use unary plus to get an unfrozen string literal.' + RESTRICT_ON_SEND = %i[dup new].freeze def_node_matcher :dup_string?, <<~PATTERN (send {str dstr} :dup) @@ -38,7 +42,21 @@ module RuboCop PATTERN def on_send(node) - add_offense(node) if dup_string?(node) || string_new?(node) + return unless dup_string?(node) || string_new?(node) + + add_offense(node) do |corrector| + corrector.replace(node, "+#{string_value(node)}") + end + end + + private + + def string_value(node) + if node.receiver.source == 'String' && node.method?(:new) + node.arguments.empty? ? "''" : node.first_argument.source + else + node.receiver.source + end end end end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/uri_default_parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/uri_default_parser.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/uri_default_parser.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/uri_default_parser.rb index add87fe820..0dc0d43b5c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance/uri_default_parser.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance/uri_default_parser.rb @@ -18,6 +18,7 @@ module RuboCop MSG = 'Use `%sURI::DEFAULT_PARSER` instead of ' \ '`%sURI::Parser.new`.' + RESTRICT_ON_SEND = %i[new].freeze def_node_matcher :uri_parser_new?, <<~PATTERN (send diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance_cops.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance_cops.rb similarity index 89% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance_cops.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance_cops.rb index b89811241f..9a37fac7ed 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/cop/performance_cops.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/cop/performance_cops.rb @@ -4,13 +4,16 @@ require_relative 'mixin/regexp_metacharacter' require_relative 'mixin/sort_block' require_relative 'performance/ancestors_include' +require_relative 'performance/array_semi_infinite_range_slice' require_relative 'performance/big_decimal_with_numeric_argument' require_relative 'performance/bind_call' +require_relative 'performance/block_given_with_explicit_block' require_relative 'performance/caller' require_relative 'performance/case_when_splat' require_relative 'performance/casecmp' require_relative 'performance/collection_literal_in_loop' require_relative 'performance/compare_with_block' +require_relative 'performance/constant_regexp' require_relative 'performance/count' require_relative 'performance/delete_prefix' require_relative 'performance/delete_suffix' @@ -20,6 +23,7 @@ require_relative 'performance/end_with' require_relative 'performance/fixed_size' require_relative 'performance/flat_map' require_relative 'performance/inefficient_hash_search' +require_relative 'performance/method_object_as_block' require_relative 'performance/open_struct' require_relative 'performance/range_include' require_relative 'performance/io_readlines' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance/inject.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance/inject.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.8.1/lib/rubocop/performance/inject.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance/inject.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance/version.rb new file mode 100644 index 0000000000..4978f563b9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.9.0/lib/rubocop/performance/version.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module RuboCop + module Performance + # This module holds the RuboCop Performance version information. + module Version + STRING = '1.9.0' + + def self.document_version + STRING.match('\d+\.\d+').to_s + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho.rb similarity index 56% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho.rb index bb0336a499..bc6773a92f 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +require "open3" + require_relative "macho/structure" require_relative "macho/view" require_relative "macho/headers" @@ -12,7 +16,7 @@ require_relative "macho/tools" # The primary namespace for ruby-macho. module MachO # release version - VERSION = "2.2.0".freeze + VERSION = "2.5.0" # Opens the given filename as a MachOFile or FatFile, depending on its magic. # @param filename [String] the file being opened @@ -25,7 +29,7 @@ module MachO raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) raise TruncatedFileError unless File.stat(filename).size >= 4 - magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first + magic = File.open(filename, "rb") { |f| f.read(4) }.unpack1("N") if Utils.fat_magic?(magic) file = FatFile.new(filename) @@ -37,4 +41,21 @@ module MachO file end + + # Signs the dylib using an ad-hoc identity. + # Necessary after making any changes to a dylib, since otherwise + # changing a signed file invalidates its signature. + # @param filename [String] the file being opened + # @return [void] + # @raise [ModificationError] if the operation fails + def self.codesign!(filename) + raise ArgumentError, "codesign binary is not available on Linux" if RUBY_PLATFORM !~ /darwin/ + raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) + + _, _, status = Open3.capture3("codesign", "--sign", "-", "--force", + "--preserve-metadata=entitlements,requirements,flags,runtime", + filename) + + raise CodeSigningError, "#{filename}: signing failed!" unless status.success? + end end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/exceptions.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/exceptions.rb similarity index 90% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/exceptions.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/exceptions.rb index a07781cbbf..b3b53e340c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/exceptions.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/exceptions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # A generic Mach-O error in execution. class MachOError < RuntimeError @@ -7,6 +9,11 @@ module MachO class ModificationError < MachOError end + # Raised when codesigning fails. Certain environments + # may want to rescue this to treat it as non-fatal. + class CodeSigningError < MachOError + end + # Raised when a Mach-O file modification fails but can be recovered when # operating on multiple Mach-O slices of a fat binary in non-strict mode. class RecoverableModificationError < ModificationError @@ -25,10 +32,6 @@ module MachO # Raised when a file is not a Mach-O. class NotAMachOError < MachOError - # @param error [String] the error in question - def initialize(error) - super error - end end # Raised when a file is too short to be a valid Mach-O file. @@ -41,8 +44,8 @@ module MachO # Raised when a file's magic bytes are not valid Mach-O magic. class MagicError < NotAMachOError # @param num [Integer] the unknown number - def initialize(num) - super "Unrecognized Mach-O magic: 0x#{"%02x" % num}" + def initialize(magic) + super "Unrecognized Mach-O magic: 0x%02x" % { :magic => magic } end end @@ -71,7 +74,7 @@ module MachO class CPUTypeError < MachOError # @param cputype [Integer] the unknown CPU type def initialize(cputype) - super "Unrecognized CPU type: 0x#{"%08x" % cputype}" + super "Unrecognized CPU type: 0x%08x" % { :cputype => cputype } end end @@ -80,8 +83,8 @@ module MachO # @param cputype [Integer] the CPU type of the unknown pair # @param cpusubtype [Integer] the CPU sub-type of the unknown pair def initialize(cputype, cpusubtype) - super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype}" \ - " (for CPU type: 0x#{"%08x" % cputype})" + super "Unrecognized CPU sub-type: 0x%08x" \ + " (for CPU type: 0x%08x" % { :cputype => cputype, :cpusubtype => cpusubtype } end end @@ -89,7 +92,7 @@ module MachO class FiletypeError < MachOError # @param num [Integer] the unknown number def initialize(num) - super "Unrecognized Mach-O filetype code: 0x#{"%02x" % num}" + super "Unrecognized Mach-O filetype code: 0x%02x" % { :num => num } end end @@ -97,7 +100,7 @@ module MachO class LoadCommandError < MachOError # @param num [Integer] the unknown number def initialize(num) - super "Unrecognized Mach-O load command: 0x#{"%02x" % num}" + super "Unrecognized Mach-O load command: 0x%02x" % { :num => num } end end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/fat_file.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/fat_file.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/fat_file.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/fat_file.rb index 809f647ca1..0eecdcf326 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/fat_file.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/fat_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "forwardable" module MachO @@ -64,7 +66,7 @@ module MachO offset += (macho.serialize.bytesize + macho_pads[macho]) end - machos.each do |macho| + machos.each do |macho| # rubocop:disable Style/CombinableLoops bin << Utils.nullpad(macho_pads[macho]) bin << macho.serialize end @@ -396,16 +398,14 @@ module MachO errors = [] machos.each_with_index do |macho, index| - begin - yield macho - rescue RecoverableModificationError => error - error.macho_slice = index + yield macho + rescue RecoverableModificationError => e + e.macho_slice = index - # Strict mode: Immediately re-raise. Otherwise: Retain, check later. - raise error if strict + # Strict mode: Immediately re-raise. Otherwise: Retain, check later. + raise e if strict - errors << error - end + errors << e end # Non-strict mode: Raise first error if *all* Mach-O slices failed. diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/headers.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/headers.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/headers.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/headers.rb index 0a940e405c..a7ed2cacf3 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/headers.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/headers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # Classes and constants for parsing the headers of Mach-O binaries. module Headers @@ -490,7 +492,7 @@ module MachO # always big-endian # @see MachOStructure::FORMAT # @api private - FORMAT = "N2".freeze + FORMAT = "N2" # @see MachOStructure::SIZEOF # @api private @@ -498,6 +500,7 @@ module MachO # @api private def initialize(magic, nfat_arch) + super() @magic = magic @nfat_arch = nfat_arch end @@ -541,7 +544,7 @@ module MachO # @note Always big endian. # @see MachOStructure::FORMAT # @api private - FORMAT = "L>5".freeze + FORMAT = "L>5" # @see MachOStructure::SIZEOF # @api private @@ -549,6 +552,7 @@ module MachO # @api private def initialize(cputype, cpusubtype, offset, size, align) + super() @cputype = cputype @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK @offset = offset @@ -587,7 +591,7 @@ module MachO # @note Always big endian. # @see MachOStructure::FORMAT # @api private - FORMAT = "L>2Q>2L>2".freeze + FORMAT = "L>2Q>2L>2" # @see MachOStructure::SIZEOF # @api private @@ -637,7 +641,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=7".freeze + FORMAT = "L=7" # @see MachOStructure::SIZEOF # @api private @@ -646,6 +650,7 @@ module MachO # @api private def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags) + super() @magic = magic @cputype = cputype # For now we're not interested in additional capability bits also to be @@ -760,7 +765,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=8".freeze + FORMAT = "L=8" # @see MachOStructure::SIZEOF # @api private diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/load_commands.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/load_commands.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/load_commands.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/load_commands.rb index 394a0c6717..aa90c0b7cf 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/load_commands.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/load_commands.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # Classes and constants for parsing load commands in Mach-O binaries. module LoadCommands @@ -60,6 +62,8 @@ module MachO 0x30 => :LC_VERSION_MIN_WATCHOS, 0x31 => :LC_NOTE, 0x32 => :LC_BUILD_VERSION, + (0x33 | LC_REQ_DYLD) => :LC_DYLD_EXPORTS_TRIE, + (0x34 | LC_REQ_DYLD) => :LD_DYLD_CHAINED_FIXUPS, }.freeze # association of symbol representations to load command constants @@ -145,6 +149,8 @@ module MachO :LC_VERSION_MIN_WATCHOS => "VersionMinCommand", :LC_NOTE => "NoteCommand", :LC_BUILD_VERSION => "BuildVersionCommand", + :LC_DYLD_EXPORTS_TRIE => "LinkeditDataCommand", + :LD_DYLD_CHAINED_FIXUPS => "LinkeditDataCommand", }.freeze # association of segment name symbols to names @@ -186,7 +192,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2".freeze + FORMAT = "L=2" # @see MachOStructure::SIZEOF # @api private @@ -225,6 +231,7 @@ module MachO # @param cmdsize [Integer] the size of the load command in bytes # @api private def initialize(view, cmd, cmdsize) + super() @view = view @cmd = cmd @cmdsize = cmdsize @@ -365,7 +372,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2a16".freeze + FORMAT = "L=2a16" # @see MachOStructure::SIZEOF # @api private @@ -379,7 +386,7 @@ module MachO # @return [String] a string representation of the UUID def uuid_string - hexes = uuid.map { |e| "%02x" % e } + hexes = uuid.map { |elem| "%02x" % { :elem => elem } } segs = [ hexes[0..3].join, hexes[4..5].join, hexes[6..7].join, hexes[8..9].join, hexes[10..15].join @@ -429,7 +436,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2Z16L=4l=2L=2".freeze + FORMAT = "L=2Z16L=4l=2L=2" # @see MachOStructure::SIZEOF # @api private @@ -524,7 +531,7 @@ module MachO class SegmentCommand64 < SegmentCommand # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2Z16Q=4l=2L=2".freeze + FORMAT = "L=2Z16Q=4l=2L=2" # @see MachOStructure::SIZEOF # @api private @@ -550,7 +557,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=6".freeze + FORMAT = "L=6" # @see MachOStructure::SIZEOF # @api private @@ -601,7 +608,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -649,7 +656,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=5".freeze + FORMAT = "L=5" # @see MachOStructure::SIZEOF # @api private @@ -679,7 +686,7 @@ module MachO class ThreadCommand < LoadCommand # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2".freeze + FORMAT = "L=2" # @see MachOStructure::SIZEOF # @api private @@ -717,7 +724,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=10".freeze + FORMAT = "L=10" # @see MachOStructure::SIZEOF # @api private @@ -758,7 +765,7 @@ module MachO class RoutinesCommand64 < RoutinesCommand # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2Q=8".freeze + FORMAT = "L=2Q=8" # @see MachOStructure::SIZEOF # @api private @@ -773,7 +780,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -801,7 +808,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -829,7 +836,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -857,7 +864,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -894,7 +901,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=6".freeze + FORMAT = "L=6" # @see MachOStructure::SIZEOF # @api private @@ -979,7 +986,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=20".freeze + FORMAT = "L=20" # @see MachOStructure::SIZEOF # @api private @@ -1052,7 +1059,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=4".freeze + FORMAT = "L=4" # @see MachOStructure::SIZEOF # @api private @@ -1127,7 +1134,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -1156,7 +1163,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -1191,7 +1198,8 @@ module MachO # A load command representing the offsets and sizes of a blob of data in # the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE, # LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, - # LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT. + # LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE, + # or LC_DYLD_CHAINED_FIXUPS. class LinkeditDataCommand < LoadCommand # @return [Integer] offset to the data in the __LINKEDIT segment attr_reader :dataoff @@ -1201,7 +1209,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=4".freeze + FORMAT = "L=4" # @see MachOStructure::SIZEOF # @api private @@ -1237,7 +1245,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=5".freeze + FORMAT = "L=5" # @see MachOStructure::SIZEOF # @api private @@ -1269,7 +1277,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=6".freeze + FORMAT = "L=6" # @see MachOStructure::SIZEOF # @api private @@ -1301,7 +1309,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=4".freeze + FORMAT = "L=4" # @see MachOStructure::SIZEOF # @api private @@ -1317,7 +1325,7 @@ module MachO # A string representation of the binary's minimum OS version. # @return [String] a string representing the minimum OS version. def version_string - binary = "%032b" % version + binary = "%032b" % { :version => version } segs = [ binary[0..15], binary[16..23], binary[24..31] ].map { |s| s.to_i(2) } @@ -1328,7 +1336,7 @@ module MachO # A string representation of the binary's SDK version. # @return [String] a string representing the SDK version. def sdk_string - binary = "%032b" % sdk + binary = "%032b" % { :sdk => sdk } segs = [ binary[0..15], binary[16..23], binary[24..31] ].map { |s| s.to_i(2) } @@ -1365,7 +1373,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=6".freeze + FORMAT = "L=6" # @see MachOStructure::SIZEOF # @api private @@ -1383,7 +1391,7 @@ module MachO # A string representation of the binary's minimum OS version. # @return [String] a string representing the minimum OS version. def minos_string - binary = "%032b" % minos + binary = "%032b" % { :minos => minos } segs = [ binary[0..15], binary[16..23], binary[24..31] ].map { |s| s.to_i(2) } @@ -1394,7 +1402,7 @@ module MachO # A string representation of the binary's SDK version. # @return [String] a string representing the SDK version. def sdk_string - binary = "%032b" % sdk + binary = "%032b" % { :sdk => sdk } segs = [ binary[0..15], binary[16..23], binary[24..31] ].map { |s| s.to_i(2) } @@ -1494,7 +1502,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=12".freeze + FORMAT = "L=12" # @see MachOStructure::SIZEOF # @api private @@ -1542,7 +1550,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=3".freeze + FORMAT = "L=3" # @see MachOStructure::SIZEOF # @api private @@ -1572,7 +1580,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2Q=2".freeze + FORMAT = "L=2Q=2" # @see MachOStructure::SIZEOF # @api private @@ -1602,7 +1610,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2Q=1".freeze + FORMAT = "L=2Q=1" # @see MachOStructure::SIZEOF # @api private @@ -1617,7 +1625,7 @@ module MachO # A string representation of the sources used to build the binary. # @return [String] a string representation of the version def version_string - binary = "%064b" % version + binary = "%064b" % { :version => version } segs = [ binary[0..23], binary[24..33], binary[34..43], binary[44..53], binary[54..63] @@ -1646,7 +1654,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=4".freeze + FORMAT = "L=4" # @see MachOStructure::SIZEOF # @api private @@ -1674,7 +1682,7 @@ module MachO class IdentCommand < LoadCommand # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2".freeze + FORMAT = "L=2" # @see MachOStructure::SIZEOF # @api private @@ -1692,7 +1700,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=4".freeze + FORMAT = "L=4" # @see MachOStructure::SIZEOF # @api private @@ -1727,7 +1735,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=5".freeze + FORMAT = "L=5" # @see MachOStructure::SIZEOF # @api private @@ -1764,7 +1772,7 @@ module MachO # @see MachOStructure::FORMAT # @api private - FORMAT = "L=2Z16Q=2".freeze + FORMAT = "L=2Z16Q=2" # @see MachOStructure::SIZEOF # @api private diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/macho_file.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/macho_file.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/macho_file.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/macho_file.rb index dc5bb3b914..041111ad3b 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/macho_file.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/macho_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "forwardable" module MachO @@ -476,7 +478,7 @@ module MachO # @raise [FatBinaryError] if the magic is for a Fat file # @api private def populate_and_check_magic - magic = @raw_data[0..3].unpack("N").first + magic = @raw_data[0..3].unpack1("N") raise MagicError, magic unless Utils.magic?(magic) raise FatBinaryError if Utils.fat_magic?(magic) @@ -522,7 +524,7 @@ module MachO header.ncmds.times do fmt = Utils.specialize_format("L=", endianness) - cmd = @raw_data.slice(offset, 4).unpack(fmt).first + cmd = @raw_data.slice(offset, 4).unpack1(fmt) cmd_sym = LoadCommands::LOAD_COMMANDS[cmd] raise LoadCommandError, cmd unless cmd_sym || permissive diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/sections.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/sections.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/sections.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/sections.rb index 093fbb2f88..d53811a25a 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/sections.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/sections.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # Classes and constants for parsing sections in Mach-O binaries. module Sections @@ -108,7 +110,7 @@ module MachO attr_reader :reserved2 # @see MachOStructure::FORMAT - FORMAT = "Z16Z16L=9".freeze + FORMAT = "Z16Z16L=9" # @see MachOStructure::SIZEOF SIZEOF = 68 @@ -116,6 +118,7 @@ module MachO # @api private def initialize(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2) + super() @sectname = sectname @segname = segname @addr = addr @@ -180,7 +183,7 @@ module MachO attr_reader :reserved3 # @see MachOStructure::FORMAT - FORMAT = "Z16Z16Q=2L=8".freeze + FORMAT = "Z16Z16Q=2L=8" # @see MachOStructure::SIZEOF SIZEOF = 80 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/structure.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/structure.rb similarity index 95% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/structure.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/structure.rb index 7bece4d704..0356d605af 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/structure.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/structure.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # A general purpose pseudo-structure. # @abstract @@ -5,7 +7,7 @@ module MachO # The String#unpack format of the data structure. # @return [String] the unpacking format # @api private - FORMAT = "".freeze + FORMAT = "" # The size of the data structure, in bytes. # @return [Integer] the size, in bytes diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/tools.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/tools.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/tools.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/tools.rb index c9bcbd7407..2bb05fdd6d 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/tools.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/tools.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # A collection of convenient methods for common operations on Mach-O and Fat # binaries. diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/utils.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/utils.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/utils.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/utils.rb index fb41806041..362e4dbf03 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/utils.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/utils.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # A collection of utility functions used throughout ruby-macho. module Utils @@ -51,7 +53,7 @@ module MachO def self.pack_strings(fixed_offset, alignment, strings = {}) offsets = {} next_offset = fixed_offset - payload = "" + payload = +"" strings.each do |key, string| offsets[key] = next_offset @@ -61,7 +63,7 @@ module MachO end payload << Utils.nullpad(padding_for(fixed_offset + payload.bytesize, alignment)) - [payload, offsets] + [payload.freeze, offsets] end # Compares the given number to valid Mach-O magic numbers. diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/view.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/view.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/view.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/view.rb index 5bd40e7f0e..ad68ee30ed 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.2.0/lib/macho/view.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/ruby-macho-2.5.0/lib/macho/view.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MachO # A representation of some unspecified Mach-O data. class MachOView diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_timezone_info.rb deleted file mode 100644 index 4688ca6157..0000000000 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_timezone_info.rb +++ /dev/null @@ -1,300 +0,0 @@ -module TZInfo - # Use send as a workaround for erroneous 'wrong number of arguments' errors - # with JRuby 9.0.5.0 when calling methods with Java implementations. See #114. - send(:using, RubyCoreSupport::UntaintExt) if RubyCoreSupport.const_defined?(:UntaintExt) - - # An InvalidZoneinfoFile exception is raised if an attempt is made to load an - # invalid zoneinfo file. - class InvalidZoneinfoFile < StandardError - end - - # Represents a timezone defined by a compiled zoneinfo TZif (\0, 2 or 3) file. - # - # @private - class ZoneinfoTimezoneInfo < TransitionDataTimezoneInfo #:nodoc: - - # Minimum supported timestamp (inclusive). - # - # Time.utc(1700, 1, 1).to_i - MIN_TIMESTAMP = -8520336000 - - # Maximum supported timestamp (exclusive). - # - # Time.utc(2500, 1, 1).to_i - MAX_TIMESTAMP = 16725225600 - - # Constructs the new ZoneinfoTimezoneInfo with an identifier and path - # to the file. - def initialize(identifier, file_path) - super(identifier) - - File.open(file_path, 'rb') do |file| - parse(file) - end - end - - private - # Unpack will return unsigned 32-bit integers. Translate to - # signed 32-bit. - def make_signed_int32(long) - long >= 0x80000000 ? long - 0x100000000 : long - end - - # Unpack will return a 64-bit integer as two unsigned 32-bit integers - # (most significant first). Translate to signed 64-bit - def make_signed_int64(high, low) - unsigned = (high << 32) | low - unsigned >= 0x8000000000000000 ? unsigned - 0x10000000000000000 : unsigned - end - - # Read bytes from file and check that the correct number of bytes could - # be read. Raises InvalidZoneinfoFile if the number of bytes didn't match - # the number requested. - def check_read(file, bytes) - result = file.read(bytes) - - unless result && result.length == bytes - raise InvalidZoneinfoFile, "Expected #{bytes} bytes reading '#{file.path}', but got #{result ? result.length : 0} bytes" - end - - result - end - - # Zoneinfo files don't include the offset from standard time (std_offset) - # for DST periods. Derive the base offset (utc_offset) where DST is - # observed from either the previous or next non-DST period. - # - # Returns the index of the offset to be used prior to the first - # transition. - def derive_offsets(transitions, offsets) - # The first non-DST offset (if there is one) is the offset observed - # before the first transition. Fallback to the first DST offset if there - # are no non-DST offsets. - first_non_dst_offset_index = offsets.index {|o| !o[:is_dst] } - first_offset_index = first_non_dst_offset_index || 0 - return first_offset_index if transitions.empty? - - # Determine the utc_offset of the next non-dst offset at each transition. - utc_offset_from_next = nil - - transitions.reverse_each do |transition| - offset = offsets[transition[:offset]] - if offset[:is_dst] - transition[:utc_offset_from_next] = utc_offset_from_next if utc_offset_from_next - else - utc_offset_from_next = offset[:utc_total_offset] - end - end - - utc_offset_from_previous = first_non_dst_offset_index ? offsets[first_non_dst_offset_index][:utc_total_offset] : nil - defined_offsets = {} - - transitions.each do |transition| - offset_index = transition[:offset] - offset = offsets[offset_index] - utc_total_offset = offset[:utc_total_offset] - - if offset[:is_dst] - utc_offset_from_next = transition[:utc_offset_from_next] - - difference_to_previous = (utc_total_offset - (utc_offset_from_previous || utc_total_offset)).abs - difference_to_next = (utc_total_offset - (utc_offset_from_next || utc_total_offset)).abs - - utc_offset = if difference_to_previous == 3600 - utc_offset_from_previous - elsif difference_to_next == 3600 - utc_offset_from_next - elsif difference_to_previous > 0 && difference_to_next > 0 - difference_to_previous < difference_to_next ? utc_offset_from_previous : utc_offset_from_next - elsif difference_to_previous > 0 - utc_offset_from_previous - elsif difference_to_next > 0 - utc_offset_from_next - else - # No difference, assume a 1 hour offset from standard time. - utc_total_offset - 3600 - end - - if !offset[:utc_offset] - offset[:utc_offset] = utc_offset - defined_offsets[offset] = offset_index - elsif offset[:utc_offset] != utc_offset - # An earlier transition has already derived a different - # utc_offset. Define a new offset or reuse an existing identically - # defined offset. - new_offset = offset.dup - new_offset[:utc_offset] = utc_offset - - offset_index = defined_offsets[new_offset] - - unless offset_index - offsets << new_offset - offset_index = offsets.length - 1 - defined_offsets[new_offset] = offset_index - end - - transition[:offset] = offset_index - end - else - utc_offset_from_previous = utc_total_offset - end - end - - first_offset_index - end - - # Defines an offset for the timezone based on the given index and offset - # Hash. - def define_offset(index, offset) - utc_total_offset = offset[:utc_total_offset] - utc_offset = offset[:utc_offset] - - if utc_offset - # DST offset with base utc_offset derived by derive_offsets. - std_offset = utc_total_offset - utc_offset - elsif offset[:is_dst] - # DST offset unreferenced by a transition (offset in use before the - # first transition). No derived base UTC offset, so assume 1 hour - # DST. - utc_offset = utc_total_offset - 3600 - std_offset = 3600 - else - # Non-DST offset. - utc_offset = utc_total_offset - std_offset = 0 - end - - offset index, utc_offset, std_offset, offset[:abbr].untaint.to_sym - end - - # Parses a zoneinfo file and intializes the DataTimezoneInfo structures. - def parse(file) - magic, version, ttisgmtcnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = - check_read(file, 44).unpack('a4 a x15 NNNNNN') - - if magic != 'TZif' - raise InvalidZoneinfoFile, "The file '#{file.path}' does not start with the expected header." - end - - if (version == '2' || version == '3') && RubyCoreSupport.time_supports_64bit - # Skip the first 32-bit section and read the header of the second 64-bit section - file.seek(timecnt * 5 + typecnt * 6 + charcnt + leapcnt * 8 + ttisgmtcnt + ttisstdcnt, IO::SEEK_CUR) - - prev_version = version - - magic, version, ttisgmtcnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = - check_read(file, 44).unpack('a4 a x15 NNNNNN') - - unless magic == 'TZif' && (version == prev_version) - raise InvalidZoneinfoFile, "The file '#{file.path}' contains an invalid 64-bit section header." - end - - using_64bit = true - elsif version != '3' && version != '2' && version != "\0" - raise InvalidZoneinfoFile, "The file '#{file.path}' contains a version of the zoneinfo format that is not currently supported." - else - using_64bit = false - end - - unless leapcnt == 0 - raise InvalidZoneinfoFile, "The zoneinfo file '#{file.path}' contains leap second data. TZInfo requires zoneinfo files that omit leap seconds." - end - - transitions = [] - - if using_64bit - timecnt.times do |i| - high, low = check_read(file, 8).unpack('NN'.freeze) - transition_time = make_signed_int64(high, low) - transitions << {:at => transition_time} - end - else - timecnt.times do |i| - transition_time = make_signed_int32(check_read(file, 4).unpack('N'.freeze)[0]) - transitions << {:at => transition_time} - end - end - - timecnt.times do |i| - localtime_type = check_read(file, 1).unpack('C'.freeze)[0] - transitions[i][:offset] = localtime_type - end - - offsets = [] - - typecnt.times do |i| - gmtoff, isdst, abbrind = check_read(file, 6).unpack('NCC'.freeze) - gmtoff = make_signed_int32(gmtoff) - isdst = isdst == 1 - offset = {:utc_total_offset => gmtoff, :is_dst => isdst, :abbr_index => abbrind} - - unless isdst - offset[:utc_offset] = gmtoff - offset[:std_offset] = 0 - end - - offsets << offset - end - - abbrev = check_read(file, charcnt) - - offsets.each do |o| - abbrev_start = o[:abbr_index] - raise InvalidZoneinfoFile, "Abbreviation index is out of range in file '#{file.path}'" unless abbrev_start < abbrev.length - - abbrev_end = abbrev.index("\0", abbrev_start) - raise InvalidZoneinfoFile, "Missing abbreviation null terminator in file '#{file.path}'" unless abbrev_end - - o[:abbr] = RubyCoreSupport.force_encoding(abbrev[abbrev_start...abbrev_end], 'UTF-8') - end - - transitions.each do |t| - if t[:offset] < 0 || t[:offset] >= offsets.length - raise InvalidZoneinfoFile, "Invalid offset referenced by transition in file '#{file.path}'." - end - end - - # Derive the offsets from standard time (std_offset). - first_offset_index = derive_offsets(transitions, offsets) - - define_offset(first_offset_index, offsets[first_offset_index]) - - offsets.each_with_index do |o, i| - define_offset(i, o) unless i == first_offset_index - end - - if !using_64bit && !RubyCoreSupport.time_supports_negative - # Filter out transitions that are not supported by Time on this - # platform. - - # Move the last transition before the epoch up to the epoch. This - # allows for accurate conversions for all supported timestamps on the - # platform. - - before_epoch, after_epoch = transitions.partition {|t| t[:at] < 0} - - if before_epoch.length > 0 && after_epoch.length > 0 && after_epoch.first[:at] != 0 - last_before = before_epoch.last - last_before[:at] = 0 - transitions = [last_before] + after_epoch - else - transitions = after_epoch - end - end - - # Ignore transitions that occur outside of a defined window. The - # transition index cannot handle a large range of transition times. - # - # This is primarily intended to ignore the far in the past transition - # added in zic 2014c (at timestamp -2**63 in zic 2014c and at the - # approximate time of the big bang from zic 2014d). - transitions.each do |t| - at = t[:at] - if at >= MIN_TIMESTAMP && at < MAX_TIMESTAMP - time = Time.at(at).utc - transition time.year, time.mon, t[:offset], at - end - end - end - end -end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo.rb similarity index 91% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo.rb index 0b64589bec..7a11ef77e6 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo.rb @@ -10,6 +10,8 @@ require 'tzinfo/timezone_definition' require 'tzinfo/timezone_offset' require 'tzinfo/timezone_transition' +require 'tzinfo/transition_rule' +require 'tzinfo/annual_rules' require 'tzinfo/timezone_transition_definition' require 'tzinfo/timezone_index_definition' @@ -22,6 +24,7 @@ require 'tzinfo/zoneinfo_timezone_info' require 'tzinfo/data_source' require 'tzinfo/ruby_data_source' +require 'tzinfo/posix_time_zone_parser' require 'tzinfo/zoneinfo_data_source' require 'tzinfo/timezone_period' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/annual_rules.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/annual_rules.rb new file mode 100644 index 0000000000..fec436b7a2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/annual_rules.rb @@ -0,0 +1,51 @@ +module TZInfo + # A set of rules that define when transitions occur in time zones with + # annually occurring daylight savings time. + # + # @private + class AnnualRules #:nodoc: + # Returned by #transitions. #offset is the TimezoneOffset that applies + # from the UTC TimeOrDateTime #at. #previous_offset is the prior + # TimezoneOffset. + Transition = Struct.new(:offset, :previous_offset, :at) + + # The standard offset that applies when daylight savings time is not in + # force. + attr_reader :std_offset + + # The offset that applies when daylight savings time is in force. + attr_reader :dst_offset + + # The rule that determines when daylight savings time starts. + attr_reader :dst_start_rule + + # The rule that determines when daylight savings time ends. + attr_reader :dst_end_rule + + # Initializes a new {AnnualRules} instance. + def initialize(std_offset, dst_offset, dst_start_rule, dst_end_rule) + @std_offset = std_offset + @dst_offset = dst_offset + @dst_start_rule = dst_start_rule + @dst_end_rule = dst_end_rule + end + + # Returns the transitions between standard and daylight savings time for a + # given year. The results are ordered by time of occurrence (earliest to + # latest). + def transitions(year) + start_dst = apply_rule(@dst_start_rule, @std_offset, @dst_offset, year) + end_dst = apply_rule(@dst_end_rule, @dst_offset, @std_offset, year) + + end_dst.at < start_dst.at ? [end_dst, start_dst] : [start_dst, end_dst] + end + + private + + # Applies a given rule between offsets on a year. + def apply_rule(rule, from_offset, to_offset, year) + at = rule.at(from_offset, year) + Transition.new(to_offset, from_offset, at) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_index_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country_index_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_index_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country_index_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/country_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_source.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/data_source.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_source.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/data_source.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/data_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/data_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/data_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/data_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/info_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/info_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/info_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/info_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/linked_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/linked_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/linked_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/linked_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/linked_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/linked_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/linked_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/linked_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/offset_rationals.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/offset_rationals.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/offset_rationals.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/offset_rationals.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/posix_time_zone_parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/posix_time_zone_parser.rb new file mode 100644 index 0000000000..af2d7e0185 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/posix_time_zone_parser.rb @@ -0,0 +1,136 @@ +# encoding: UTF-8 +# frozen_string_literal: true + +require 'strscan' + +module TZInfo + # An {InvalidPosixTimeZone} exception is raised if an invalid POSIX-style + # time zone string is encountered. + # + # @private + class InvalidPosixTimeZone < StandardError #:nodoc: + end + + # A parser for POSIX-style TZ strings used in zoneinfo files and specified + # by tzfile.5 and tzset.3. + # + # @private + class PosixTimeZoneParser #:nodoc: + # Parses a POSIX-style TZ string, returning either a TimezoneOffset or + # an AnnualRules instance. + def parse(tz_string) + raise InvalidPosixTimeZone unless tz_string.kind_of?(String) + return nil if tz_string.empty? + + s = StringScanner.new(tz_string) + check_scan(s, /([^-+,\d<][^-+,\d]*) | <([^>]+)>/x) + std_abbrev = s[1] || s[2] + check_scan(s, /([-+]?\d+)(?::(\d+)(?::(\d+))?)?/) + std_offset = get_offset_from_hms(s[1], s[2], s[3]) + + if s.scan(/([^-+,\d<][^-+,\d]*) | <([^>]+)>/x) + dst_abbrev = s[1] || s[2] + + if s.scan(/([-+]?\d+)(?::(\d+)(?::(\d+))?)?/) + dst_offset = get_offset_from_hms(s[1], s[2], s[3]) + else + # POSIX is negative for ahead of UTC. + dst_offset = std_offset - 3600 + end + + dst_difference = std_offset - dst_offset + + start_rule = parse_rule(s, 'start') + end_rule = parse_rule(s, 'end') + + raise InvalidPosixTimeZone, "Expected the end of a POSIX-style time zone string but found '#{s.rest}'." if s.rest? + + if start_rule.is_always_first_day_of_year? && start_rule.transition_at == 0 && + end_rule.is_always_last_day_of_year? && end_rule.transition_at == 86400 + dst_difference + # Constant daylight savings time. + # POSIX is negative for ahead of UTC. + TimezoneOffset.new(-std_offset, dst_difference, dst_abbrev.to_sym) + else + AnnualRules.new( + TimezoneOffset.new(-std_offset, 0, std_abbrev.to_sym), + TimezoneOffset.new(-std_offset, dst_difference, dst_abbrev.to_sym), + start_rule, + end_rule) + end + elsif !s.rest? + # Constant standard time. + # POSIX is negative for ahead of UTC. + TimezoneOffset.new(-std_offset, 0, std_abbrev.to_sym) + else + raise InvalidPosixTimeZone, "Expected the end of a POSIX-style time zone string but found '#{s.rest}'." + end + end + + private + + # Parses the rule from the TZ string, returning a TransitionRule. + def parse_rule(s, type) + check_scan(s, /,(?: (?: J(\d+) ) | (\d+) | (?: M(\d+)\.(\d)\.(\d) ) )/x) + julian_day_of_year = s[1] + absolute_day_of_year = s[2] + month = s[3] + week = s[4] + day_of_week = s[5] + + if s.scan(/\//) + check_scan(s, /([-+]?\d+)(?::(\d+)(?::(\d+))?)?/) + transition_at = get_seconds_after_midnight_from_hms(s[1], s[2], s[3]) + else + transition_at = 7200 + end + + begin + if julian_day_of_year + JulianDayOfYearTransitionRule.new(julian_day_of_year.to_i, transition_at) + elsif absolute_day_of_year + AbsoluteDayOfYearTransitionRule.new(absolute_day_of_year.to_i, transition_at) + elsif week == '5' + LastDayOfMonthTransitionRule.new(month.to_i, day_of_week.to_i, transition_at) + else + DayOfMonthTransitionRule.new(month.to_i, week.to_i, day_of_week.to_i, transition_at) + end + rescue ArgumentError => e + raise InvalidPosixTimeZone, "Invalid #{type} rule in POSIX-style time zone string: #{e}" + end + end + + # Returns an offset in seconds from hh:mm:ss values. The value can be + # negative. -02:33:12 would represent 2 hours, 33 minutes and 12 seconds + # ahead of UTC. + def get_offset_from_hms(h, m, s) + h = h.to_i + m = m.to_i + s = s.to_i + raise InvalidPosixTimeZone, "Invalid minute #{m} in offset for POSIX-style time zone string." if m > 59 + raise InvalidPosixTimeZone, "Invalid second #{s} in offset for POSIX-style time zone string." if s > 59 + magnitude = (h.abs * 60 + m) * 60 + s + h < 0 ? -magnitude : magnitude + end + + # Returns the seconds from midnight from hh:mm:ss values. Hours can exceed + # 24 for a time on the following day. Hours can be negative to subtract + # hours from midnight on the given day. -02:33:12 represents 22:33:12 on + # the prior day. + def get_seconds_after_midnight_from_hms(h, m, s) + h = h.to_i + m = m.to_i + s = s.to_i + raise InvalidPosixTimeZone, "Invalid minute #{m} in time for POSIX-style time zone string." if m > 59 + raise InvalidPosixTimeZone, "Invalid second #{s} in time for POSIX-style time zone string." if s > 59 + (h * 3600) + m * 60 + s + end + + # Scans for a pattern and raises an exception if the pattern does not + # match the input. + def check_scan(s, pattern) + result = s.scan(pattern) + raise InvalidPosixTimeZone, "Expected '#{s.rest}' to match #{pattern} in POSIX-style time zone string." unless result + result + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_core_support.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/ruby_core_support.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_core_support.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/ruby_core_support.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_country_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/ruby_country_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_country_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/ruby_country_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_data_source.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/ruby_data_source.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_data_source.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/ruby_data_source.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/time_or_datetime.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/time_or_datetime.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/time_or_datetime.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/time_or_datetime.rb index f358005f8e..56c33147bb 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/time_or_datetime.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/time_or_datetime.rb @@ -160,6 +160,17 @@ module TZInfo end end alias :day :mday + + # Returns the day of the week (0..6 for Sunday to Saturday). + def wday + if @time + @time.wday + elsif @datetime + @datetime.wday + else + to_time.wday + end + end # Returns the hour of the day (0..23). def hour diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_index_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_index_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_index_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_index_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_offset.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_offset.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_offset.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_period.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_period.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_period.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_period.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_proxy.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_proxy.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_proxy.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_proxy.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_transition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_transition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_transition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_transition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_transition_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_transition_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_transition_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/timezone_transition_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/transition_data_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/transition_data_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/transition_data_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/transition_data_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/transition_rule.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/transition_rule.rb new file mode 100644 index 0000000000..b8d160528b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/transition_rule.rb @@ -0,0 +1,325 @@ +require 'date' + +module TZInfo + # Base class for rules definining the transition between standard and daylight + # savings time. + class TransitionRule #:nodoc: + # Returns the number of seconds after midnight local time on the day + # identified by the rule at which the transition occurs. Can be negative to + # denote a time on the prior day. Can be greater than or equal to 86,400 to + # denote a time of the following day. + attr_reader :transition_at + + # Initializes a new TransitionRule. + def initialize(transition_at) + raise ArgumentError, 'Invalid transition_at' unless transition_at.kind_of?(Integer) + @transition_at = transition_at + end + + # Calculates the UTC time of the transition from a given offset on a given + # year. + def at(offset, year) + day = get_day(year) + day.add_with_convert(@transition_at - offset.utc_total_offset) + end + + # Determines if this TransitionRule is equal to another instance. + def ==(r) + r.kind_of?(TransitionRule) && @transition_at == r.transition_at + end + alias eql? == + + # Returns a hash based on hash_args (defaulting to transition_at). + def hash + hash_args.hash + end + + protected + + # Returns an Array of parameters that will influence the output of hash. + def hash_args + [@transition_at] + end + + def new_time_or_datetime(year, month = 1, day = 1) + result = if ((year >= 2039 || (year == 2038 && (month >= 2 || (month == 1 && day >= 20)))) && !RubyCoreSupport.time_supports_64bit) || + (year < 1970 && !RubyCoreSupport.time_supports_negative) + + # Time handles 29 February on a non-leap year as 1 March. + # DateTime rejects. Advance manually. + if month == 2 && day == 29 && !Date.gregorian_leap?(year) + month = 3 + day = 1 + end + + RubyCoreSupport.datetime_new(year, month, day) + else + Time.utc(year, month, day) + end + + TimeOrDateTime.wrap(result) + end + end + + # A base class for transition rules that activate based on an integer day of + # the year. + # + # @private + class DayOfYearTransitionRule < TransitionRule #:nodoc: + # Initializes a new DayOfYearTransitionRule. + def initialize(day, transition_at) + super(transition_at) + raise ArgumentError, 'Invalid day' unless day.kind_of?(Integer) + @seconds = day * 86400 + end + + # Determines if this DayOfYearTransitionRule is equal to another instance. + def ==(r) + super(r) && r.kind_of?(DayOfYearTransitionRule) && @seconds == r.seconds + end + alias eql? == + + protected + + # @return [Integer] the day multipled by the number of seconds in a day. + attr_reader :seconds + + # Returns an Array of parameters that will influence the output of hash. + def hash_args + [@seconds] + super + end + end + + # Defines transitions that occur on the zero-based nth day of the year. + # + # Day 0 is 1 January. + # + # Leap days are counted. Day 59 will be 29 February on a leap year and 1 March + # on a non-leap year. Day 365 will be 31 December on a leap year and 1 January + # the following year on a non-leap year. + # + # @private + class AbsoluteDayOfYearTransitionRule < DayOfYearTransitionRule #:nodoc: + # Initializes a new AbsoluteDayOfYearTransitionRule. + def initialize(day, transition_at = 0) + super(day, transition_at) + raise ArgumentError, 'Invalid day' unless day >= 0 && day <= 365 + end + + # Returns true if the day specified by this transition is the first in the + # year (a day number of 0), otherwise false. + def is_always_first_day_of_year? + seconds == 0 + end + + # @returns false. + def is_always_last_day_of_year? + false + end + + # Determines if this AbsoluteDayOfYearTransitionRule is equal to another + # instance. + def ==(r) + super(r) && r.kind_of?(AbsoluteDayOfYearTransitionRule) + end + alias eql? == + + protected + + # Returns a TimeOrDateTime representing midnight local time on the day + # specified by the rule for the given offset and year. + def get_day(year) + new_time_or_datetime(year).add_with_convert(seconds) + end + + # Returns an Array of parameters that will influence the output of hash. + def hash_args + [AbsoluteDayOfYearTransitionRule] + super + end + end + + # Defines transitions that occur on the one-based nth Julian day of the year. + # + # Leap days are not counted. Day 1 is 1 January. Day 60 is always 1 March. + # Day 365 is always 31 December. + # + # @private + class JulianDayOfYearTransitionRule < DayOfYearTransitionRule #:nodoc: + # The 60 days in seconds. + LEAP = 60 * 86400 + + # The length of a non-leap year in seconds. + YEAR = 365 * 86400 + + # Initializes a new JulianDayOfYearTransitionRule. + def initialize(day, transition_at = 0) + super(day, transition_at) + raise ArgumentError, 'Invalid day' unless day >= 1 && day <= 365 + end + + # Returns true if the day specified by this transition is the first in the + # year (a day number of 1), otherwise false. + def is_always_first_day_of_year? + seconds == 86400 + end + + # Returns true if the day specified by this transition is the last in the + # year (a day number of 365), otherwise false. + def is_always_last_day_of_year? + seconds == YEAR + end + + # Determines if this JulianDayOfYearTransitionRule is equal to another + # instance. + def ==(r) + super(r) && r.kind_of?(JulianDayOfYearTransitionRule) + end + alias eql? == + + protected + + # Returns a TimeOrDateTime representing midnight local time on the day + # specified by the rule for the given offset and year. + def get_day(year) + # Returns 1 March on non-leap years. + leap = new_time_or_datetime(year, 2, 29) + diff = seconds - LEAP + diff += 86400 if diff >= 0 && leap.mday == 29 + leap.add_with_convert(diff) + end + + # Returns an Array of parameters that will influence the output of hash. + def hash_args + [JulianDayOfYearTransitionRule] + super + end + end + + # A base class for rules that transition on a particular day of week of a + # given week (subclasses specify which week of the month). + # + # @private + class DayOfWeekTransitionRule < TransitionRule #:nodoc: + # Initializes a new DayOfWeekTransitionRule. + def initialize(month, day_of_week, transition_at) + super(transition_at) + raise ArgumentError, 'Invalid month' unless month.kind_of?(Integer) && month >= 1 && month <= 12 + raise ArgumentError, 'Invalid day_of_week' unless day_of_week.kind_of?(Integer) && day_of_week >= 0 && day_of_week <= 6 + @month = month + @day_of_week = day_of_week + end + + # Returns false. + def is_always_first_day_of_year? + false + end + + # Returns false. + def is_always_last_day_of_year? + false + end + + # Determines if this DayOfWeekTransitionRule is equal to another instance. + def ==(r) + super(r) && r.kind_of?(DayOfWeekTransitionRule) && @month == r.month && @day_of_week == r.day_of_week + end + alias eql? == + + protected + + # Returns the month of the year (1 to 12). + attr_reader :month + + # Returns the day of the week (0 to 6 for Sunday to Monday). + attr_reader :day_of_week + + # Returns an Array of parameters that will influence the output of hash. + def hash_args + [@month, @day_of_week] + super + end + end + + # A rule that transitions on the nth occurrence of a particular day of week + # of a calendar month. + # + # @private + class DayOfMonthTransitionRule < DayOfWeekTransitionRule #:nodoc: + # Initializes a new DayOfMonthTransitionRule. + def initialize(month, week, day_of_week, transition_at = 0) + super(month, day_of_week, transition_at) + raise ArgumentError, 'Invalid week' unless week.kind_of?(Integer) && week >= 1 && week <= 4 + @offset_start = (week - 1) * 7 + 1 + end + + # Determines if this DayOfMonthTransitionRule is equal to another instance. + def ==(r) + super(r) && r.kind_of?(DayOfMonthTransitionRule) && @offset_start == r.offset_start + end + alias eql? == + + protected + + # Returns the day the week starts on for a month starting on a Sunday. + attr_reader :offset_start + + # Returns a TimeOrDateTime representing midnight local time on the day + # specified by the rule for the given offset and year. + def get_day(year) + candidate = new_time_or_datetime(year, month, @offset_start) + diff = day_of_week - candidate.wday + + if diff < 0 + candidate.add_with_convert((7 + diff) * 86400) + elsif diff > 0 + candidate.add_with_convert(diff * 86400) + else + candidate + end + end + + # Returns an Array of parameters that will influence the output of hash. + def hash_args + [@offset_start] + super + end + end + + # A rule that transitions on the last occurrence of a particular day of week + # of a calendar month. + # + # @private + class LastDayOfMonthTransitionRule < DayOfWeekTransitionRule #:nodoc: + # Initializes a new LastDayOfMonthTransitionRule. + def initialize(month, day_of_week, transition_at = 0) + super(month, day_of_week, transition_at) + end + + # Determines if this LastDayOfMonthTransitionRule is equal to another + # instance. + def ==(r) + super(r) && r.kind_of?(LastDayOfMonthTransitionRule) + end + alias eql? == + + protected + + # Returns a TimeOrDateTime representing midnight local time on the day + # specified by the rule for the given offset and year. + def get_day(year) + next_month = month + 1 + if next_month == 13 + year += 1 + next_month = 1 + end + + candidate = new_time_or_datetime(year, next_month).add_with_convert(-86400) + diff = candidate.wday - day_of_week + + if diff < 0 + candidate - (diff + 7) * 86400 + elsif diff > 0 + candidate - diff * 86400 + else + candidate + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_country_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_country_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_country_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_country_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_data_source.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_data_source.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_data_source.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_data_source.rb index e781d78cfa..3959090f81 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_data_source.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_data_source.rb @@ -192,6 +192,7 @@ module TZInfo @zoneinfo_dir = File.expand_path(@zoneinfo_dir).freeze @timezone_index = load_timezone_index.freeze @country_index = load_country_index(iso3166_tab_path, zone_tab_path).freeze + @posix_tz_parser = PosixTimeZoneParser.new end # Returns a TimezoneInfo instance for a given identifier. @@ -208,7 +209,7 @@ module TZInfo path.untaint begin - ZoneinfoTimezoneInfo.new(identifier, path) + ZoneinfoTimezoneInfo.new(identifier, path, @posix_tz_parser) rescue InvalidZoneinfoFile => e raise InvalidTimezoneIdentifier, e.message end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_timezone_info.rb new file mode 100644 index 0000000000..4f28a19c2a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.8/lib/tzinfo/zoneinfo_timezone_info.rb @@ -0,0 +1,515 @@ +module TZInfo + # Use send as a workaround for erroneous 'wrong number of arguments' errors + # with JRuby 9.0.5.0 when calling methods with Java implementations. See #114. + send(:using, RubyCoreSupport::UntaintExt) if RubyCoreSupport.const_defined?(:UntaintExt) + + # An InvalidZoneinfoFile exception is raised if an attempt is made to load an + # invalid zoneinfo file. + class InvalidZoneinfoFile < StandardError + end + + # Represents a timezone defined by a compiled zoneinfo TZif (\0, 2 or 3) file. + # + # @private + class ZoneinfoTimezoneInfo < TransitionDataTimezoneInfo #:nodoc: + # The year to generate transitions up to. + # + # @private + GENERATE_UP_TO = RubyCoreSupport.time_supports_64bit ? Time.now.utc.year + 100 : 2037 + + # Minimum supported timestamp (inclusive). + # + # Time.utc(1700, 1, 1).to_i + MIN_TIMESTAMP = -8520336000 + + # Maximum supported timestamp (exclusive). + # + # Time.utc(2500, 1, 1).to_i + MAX_TIMESTAMP = 16725225600 + + # Constructs the new ZoneinfoTimezoneInfo with an identifier, path + # to the file and parser to use to parse the POSIX-like TZ string. + def initialize(identifier, file_path, posix_tz_parser) + super(identifier) + + File.open(file_path, 'rb') do |file| + parse(file, posix_tz_parser) + end + end + + private + # Unpack will return unsigned 32-bit integers. Translate to + # signed 32-bit. + def make_signed_int32(long) + long >= 0x80000000 ? long - 0x100000000 : long + end + + # Unpack will return a 64-bit integer as two unsigned 32-bit integers + # (most significant first). Translate to signed 64-bit + def make_signed_int64(high, low) + unsigned = (high << 32) | low + unsigned >= 0x8000000000000000 ? unsigned - 0x10000000000000000 : unsigned + end + + # Read bytes from file and check that the correct number of bytes could + # be read. Raises InvalidZoneinfoFile if the number of bytes didn't match + # the number requested. + def check_read(file, bytes) + result = file.read(bytes) + + unless result && result.length == bytes + raise InvalidZoneinfoFile, "Expected #{bytes} bytes reading '#{file.path}', but got #{result ? result.length : 0} bytes" + end + + result + end + + # Zoneinfo files don't include the offset from standard time (std_offset) + # for DST periods. Derive the base offset (utc_offset) where DST is + # observed from either the previous or next non-DST period. + # + # Returns the index of the offset to be used prior to the first + # transition. + def derive_offsets(transitions, offsets) + # The first non-DST offset (if there is one) is the offset observed + # before the first transition. Fallback to the first DST offset if there + # are no non-DST offsets. + first_non_dst_offset_index = offsets.index {|o| !o[:is_dst] } + first_offset_index = first_non_dst_offset_index || 0 + return first_offset_index if transitions.empty? + + # Determine the utc_offset of the next non-dst offset at each transition. + utc_offset_from_next = nil + + transitions.reverse_each do |transition| + offset = offsets[transition[:offset]] + if offset[:is_dst] + transition[:utc_offset_from_next] = utc_offset_from_next if utc_offset_from_next + else + utc_offset_from_next = offset[:utc_total_offset] + end + end + + utc_offset_from_previous = first_non_dst_offset_index ? offsets[first_non_dst_offset_index][:utc_total_offset] : nil + defined_offsets = {} + + transitions.each do |transition| + offset_index = transition[:offset] + offset = offsets[offset_index] + utc_total_offset = offset[:utc_total_offset] + + if offset[:is_dst] + utc_offset_from_next = transition[:utc_offset_from_next] + + difference_to_previous = (utc_total_offset - (utc_offset_from_previous || utc_total_offset)).abs + difference_to_next = (utc_total_offset - (utc_offset_from_next || utc_total_offset)).abs + + utc_offset = if difference_to_previous == 3600 + utc_offset_from_previous + elsif difference_to_next == 3600 + utc_offset_from_next + elsif difference_to_previous > 0 && difference_to_next > 0 + difference_to_previous < difference_to_next ? utc_offset_from_previous : utc_offset_from_next + elsif difference_to_previous > 0 + utc_offset_from_previous + elsif difference_to_next > 0 + utc_offset_from_next + else + # No difference, assume a 1 hour offset from standard time. + utc_total_offset - 3600 + end + + if !offset[:utc_offset] + offset[:utc_offset] = utc_offset + defined_offsets[offset] = offset_index + elsif offset[:utc_offset] != utc_offset + # An earlier transition has already derived a different + # utc_offset. Define a new offset or reuse an existing identically + # defined offset. + new_offset = offset.dup + new_offset[:utc_offset] = utc_offset + + offset_index = defined_offsets[new_offset] + + unless offset_index + offsets << new_offset + offset_index = offsets.length - 1 + defined_offsets[new_offset] = offset_index + end + + transition[:offset] = offset_index + end + else + utc_offset_from_previous = utc_total_offset + end + end + + first_offset_index + end + + # Remove transitions before a minimum supported value. If there is not a + # transition exactly on the minimum supported value move the latest from + # before up to the minimum supported value. + def remove_unsupported_negative_transitions(transitions, min_supported) + result = transitions.drop_while {|t| t[:at] < min_supported } + if result.empty? || (result[0][:at] > min_supported && result.length < transitions.length) + last_before = transitions[-1 - result.length] + last_before[:at] = min_supported + [last_before] + result + else + result + end + end + + # Determines if the offset from a transition matches the offset from a + # rule. This is a looser match than TimezoneOffset#==, not requiring that + # the utc_offset and std_offset both match (which have to be derived for + # transitions, but are known for rules. + def offset_matches_rule?(offset, rule_offset) + offset[:utc_total_offset] == rule_offset.utc_total_offset && + offset[:is_dst] == rule_offset.dst? && + offset[:abbr] == rule_offset.abbreviation.to_s + end + + # Determins if the offset from a transition exactly matches the offset + # from a rule. + def offset_equals_rule?(offset, rule_offset) + offset_matches_rule?(offset, rule_offset) && + (offset[:utc_offset] || (offset[:is_dst] ? offset[:utc_total_offset] - 3600 : offset[:utc_total_offset])) == rule_offset.utc_offset + end + + # Finds an offset hash that is an exact match to the rule offset specified. + def find_existing_offset_index(offsets, rule_offset) + offsets.find_index {|o| offset_equals_rule?(o, rule_offset) } + end + + # Gets an existing matching offset index or adds a new offset hash for a + # rule offset. + def get_rule_offset_index(offsets, offset) + index = find_existing_offset_index(offsets, offset) + unless index + index = offsets.length + offsets << {:utc_total_offset => offset.utc_total_offset, :utc_offset => offset.utc_offset, :is_dst => offset.dst?, :abbr => offset.abbreviation} + end + index + end + + # Gets a hash mapping rule offsets to indexes in offsets, creating new + # offset hashes if required. + def get_rule_offset_indexes(offsets, annual_rules) + { + annual_rules.std_offset => get_rule_offset_index(offsets, annual_rules.std_offset), + annual_rules.dst_offset => get_rule_offset_index(offsets, annual_rules.dst_offset) + } + end + + # Converts an array of rule transitions to hashes. + def convert_transitions_to_hashes(offset_indexes, transitions) + transitions.map {|t| {:at => t.at.to_i, :offset => offset_indexes[t.offset]} } + end + + # Apply the rules from the TZ string when there were no defined + # transitions. Checks for a matching offset. Returns the rules-based + # constant offset or generates transitions from 1970 until 100 years into + # the future (at the time of loading zoneinfo_timezone_info.rb) or 2037 if + # limited to 32-bit Times. + def apply_rules_without_transitions(file, offsets, first_offset_index, rules) + first_offset = offsets[first_offset_index] + + if rules.kind_of?(TimezoneOffset) + unless offset_matches_rule?(first_offset, rules) + raise InvalidZoneinfoFile, "Constant offset POSIX-style TZ string does not match constant offset in file '#{file.path}'." + end + + first_offset[:utc_offset] = rules.utc_offset + [] + else + transitions = 1970.upto(GENERATE_UP_TO).map {|y| rules.transitions(y) }.flatten + first_transition = transitions[0] + + if offset_matches_rule?(first_offset, first_transition.previous_offset) + # Correct the first offset if it isn't an exact match. + first_offset[:utc_offset] = first_transition.previous_offset.utc_offset + else + # Not transitioning from the designated first offset. + if offset_matches_rule?(first_offset, first_transition.offset) + # Correct the first offset if it isn't an exact match. + first_offset[:utc_offset] = first_transition.offset.utc_offset + + # Skip an unnecessary transition to the first offset. + transitions.shift + end + + # If the first offset doesn't match either the offset or previous + # offset, then it will be retained. + end + + offset_indexes = get_rule_offset_indexes(offsets, rules) + convert_transitions_to_hashes(offset_indexes, transitions) + end + end + + # Validates the rules offset against the offset of the last defined + # transition. Replaces the transition with an equivalent using the rules + # offset if the rules give a different definition for the base offset. + def replace_last_transition_offset_if_valid_and_needed(file, transitions, offsets) + last_transition = transitions.last + last_offset = offsets[last_transition[:offset]] + rule_offset = yield last_offset + + unless offset_matches_rule?(last_offset, rule_offset) + raise InvalidZoneinfoFile, "Offset from POSIX-style TZ string does not match final transition in file '#{file.path}'." + end + + # The total_utc_offset and abbreviation must always be the same. The + # base utc_offset and std_offset might differ. In which case the rule + # should be used as it will be more precise. + last_offset[:utc_offset] = rule_offset.utc_offset + last_transition + end + + # todo: port over validate_and_fix_last_defined_transition_offset + # when fixing the previous offset will need to define a new one + + # Validates the offset indicated to be observed by the rules before the + # first generated transition against the offset of the last defined + # transition. + # + # Fix the last defined transition if it differ on just base/std offsets + # (which are derived). Raise an error if the observed UTC offset or + # abbreviations differ. + def validate_and_fix_last_defined_transition_offset(file, offsets, last_defined, first_rule_offset) + offset_of_last_defined = offsets[last_defined[:offset]] + + if offset_equals_rule?(offset_of_last_defined, first_rule_offset) + last_defined + else + if offset_matches_rule?(offset_of_last_defined, first_rule_offset) + # The same overall offset, but differing in the base or std + # offset (which are derived). Correct by using the rule. + + offset_index = get_rule_offset_index(offsets, first_rule_offset) + {:at => last_defined[:at], :offset => offset_index} + else + raise InvalidZoneinfoFile, "The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{file.path}'." + end + end + end + + # Apply the rules from the TZ string when there were defined transitions. + # Checks for a matching offset with the last transition. Redefines the + # last transition if required and if the rules don't specific a constant + # offset, generates transitions until 100 years into the future (at the + # time of loading zoneinfo_timezone_info.rb) or 2037 if limited to 32-bit + # Times. + def apply_rules_with_transitions(file, transitions, offsets, first_offset_index, rules) + last_defined = transitions[-1] + + if rules.kind_of?(TimezoneOffset) + transitions[-1] = validate_and_fix_last_defined_transition_offset(file, offsets, last_defined, rules) + else + previous_offset_index = transitions.length > 1 ? transitions[-2][:offset] : first_offset_index + previous_offset = offsets[previous_offset_index] + last_year = (Time.at(last_defined[:at]).utc + previous_offset[:utc_total_offset]).year + + if last_year <= GENERATE_UP_TO + generated = rules.transitions(last_year).find_all {|t| t.at > last_defined[:at] } + + (last_year + 1).upto(GENERATE_UP_TO).map {|y| rules.transitions(y) }.flatten + + unless generated.empty? + transitions[-1] = validate_and_fix_last_defined_transition_offset(file, offsets, last_defined, generated[0].previous_offset) + rule_offset_indexes = get_rule_offset_indexes(offsets, rules) + transitions.concat(convert_transitions_to_hashes(rule_offset_indexes, generated)) + end + end + end + end + + # Defines an offset for the timezone based on the given index and offset + # Hash. + def define_offset(index, offset) + utc_total_offset = offset[:utc_total_offset] + utc_offset = offset[:utc_offset] + + if utc_offset + # DST offset with base utc_offset derived by derive_offsets. + std_offset = utc_total_offset - utc_offset + elsif offset[:is_dst] + # DST offset unreferenced by a transition (offset in use before the + # first transition). No derived base UTC offset, so assume 1 hour + # DST. + utc_offset = utc_total_offset - 3600 + std_offset = 3600 + else + # Non-DST offset. + utc_offset = utc_total_offset + std_offset = 0 + end + + offset index, utc_offset, std_offset, offset[:abbr].untaint.to_sym + end + + # Parses a zoneinfo file and intializes the DataTimezoneInfo structures. + def parse(file, posix_tz_parser) + magic, version, ttisutccnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = + check_read(file, 44).unpack('a4 a x15 NNNNNN') + + if magic != 'TZif' + raise InvalidZoneinfoFile, "The file '#{file.path}' does not start with the expected header." + end + + if version == '2' || version == '3' + # Skip the first 32-bit section and read the header of the second + # 64-bit section. The 64-bit section is always used even if the + # runtime platform doesn't support 64-bit timestamps. In "slim" format + # zoneinfo files the 32-bit section will be empty. + file.seek(timecnt * 5 + typecnt * 6 + charcnt + leapcnt * 8 + ttisstdcnt + ttisutccnt, IO::SEEK_CUR) + + prev_version = version + + magic, version, ttisutccnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = + check_read(file, 44).unpack('a4 a x15 NNNNNN') + + unless magic == 'TZif' && (version == prev_version) + raise InvalidZoneinfoFile, "The file '#{file.path}' contains an invalid 64-bit section header." + end + + using_64bit = true + elsif version != '3' && version != '2' && version != "\0" + raise InvalidZoneinfoFile, "The file '#{file.path}' contains a version of the zoneinfo format that is not currently supported." + else + using_64bit = false + end + + unless leapcnt == 0 + raise InvalidZoneinfoFile, "The zoneinfo file '#{file.path}' contains leap second data. TZInfo requires zoneinfo files that omit leap seconds." + end + + transitions = [] + + if using_64bit + timecnt.times do |i| + high, low = check_read(file, 8).unpack('NN'.freeze) + transition_time = make_signed_int64(high, low) + transitions << {:at => transition_time} + end + else + timecnt.times do |i| + transition_time = make_signed_int32(check_read(file, 4).unpack('N'.freeze)[0]) + transitions << {:at => transition_time} + end + end + + timecnt.times do |i| + localtime_type = check_read(file, 1).unpack('C'.freeze)[0] + transitions[i][:offset] = localtime_type + end + + offsets = [] + + typecnt.times do |i| + gmtoff, isdst, abbrind = check_read(file, 6).unpack('NCC'.freeze) + gmtoff = make_signed_int32(gmtoff) + isdst = isdst == 1 + offset = {:utc_total_offset => gmtoff, :is_dst => isdst, :abbr_index => abbrind} + + unless isdst + offset[:utc_offset] = gmtoff + end + + offsets << offset + end + + abbrev = check_read(file, charcnt) + + if using_64bit + # Skip to the POSIX-style TZ string. + file.seek(ttisstdcnt + ttisutccnt, IO::SEEK_CUR) # + leapcnt * 8, but leapcnt is checked above and guaranteed to be 0. + tz_string_start = check_read(file, 1) + raise InvalidZoneinfoFile, "Expected newline starting POSIX-style TZ string in file '#{file.path}'." unless tz_string_start == "\n" + tz_string = RubyCoreSupport.force_encoding(file.readline("\n"), 'UTF-8') + raise InvalidZoneinfoFile, "Expected newline ending POSIX-style TZ string in file '#{file.path}'." unless tz_string.chomp!("\n") + + begin + rules = posix_tz_parser.parse(tz_string) + rescue InvalidPosixTimeZone => e + raise InvalidZoneinfoFile, "Failed to parse POSIX-style TZ string in file '#{file.path}': #{e}" + end + else + rules = nil + end + + offsets.each do |o| + abbrev_start = o[:abbr_index] + raise InvalidZoneinfoFile, "Abbreviation index is out of range in file '#{file.path}'" unless abbrev_start < abbrev.length + + abbrev_end = abbrev.index("\0", abbrev_start) + raise InvalidZoneinfoFile, "Missing abbreviation null terminator in file '#{file.path}'" unless abbrev_end + + o[:abbr] = RubyCoreSupport.force_encoding(abbrev[abbrev_start...abbrev_end], 'UTF-8') + end + + transitions.each do |t| + if t[:offset] < 0 || t[:offset] >= offsets.length + raise InvalidZoneinfoFile, "Invalid offset referenced by transition in file '#{file.path}'." + end + end + + # Derive the offsets from standard time (std_offset). + first_offset_index = derive_offsets(transitions, offsets) + + # Filter out transitions that are not supported by Time on this + # platform. + unless transitions.empty? + if !RubyCoreSupport.time_supports_negative + transitions = remove_unsupported_negative_transitions(transitions, 0) + elsif !RubyCoreSupport.time_supports_64bit + transitions = remove_unsupported_negative_transitions(transitions, -2**31) + else + # Ignore transitions that occur outside of a defined window. The + # transition index cannot handle a large range of transition times. + # + # This is primarily intended to ignore the far in the past + # transition added in zic 2014c (at timestamp -2**63 in zic 2014c + # and at the approximate time of the big bang from zic 2014d). + # + # Assumes MIN_TIMESTAMP is less than -2**31. + transitions = remove_unsupported_negative_transitions(transitions, MIN_TIMESTAMP) + end + + if !RubyCoreSupport.time_supports_64bit + i = transitions.find_index {|t| t[:at] >= 2**31 } + had_later_transition = !!i + transitions = transitions.first(i) if i + else + had_later_transition = false + end + end + + if rules && !had_later_transition + if transitions.empty? + transitions = apply_rules_without_transitions(file, offsets, first_offset_index, rules) + else + apply_rules_with_transitions(file, transitions, offsets, first_offset_index, rules) + end + end + + define_offset(first_offset_index, offsets[first_offset_index]) + + used_offset_indexes = transitions.map {|t| t[:offset] }.to_set + + offsets.each_with_index do |o, i| + define_offset(i, o) if i != first_offset_index && used_offset_indexes.include?(i) + end + + # Ignore transitions that occur outside of a defined window. The + # transition index cannot handle a large range of transition times. + transitions.each do |t| + at = t[:at] + break if at >= MAX_TIMESTAMP + time = Time.at(at).utc + transition time.year, time.mon, t[:offset], at + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/error.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/error.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/error.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/error.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/explicit_namespace.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/explicit_namespace.rb similarity index 90% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/explicit_namespace.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/explicit_namespace.rb index 2d4f015a0d..563bde3922 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/explicit_namespace.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/explicit_namespace.rb @@ -14,24 +14,22 @@ module Zeitwerk # the file system, to the loader responsible for them. # # @private - # @return [{String => Zeitwerk::Loader}] + # @sig Hash[String, Zeitwerk::Loader] attr_reader :cpaths # @private - # @return [Mutex] + # @sig Mutex attr_reader :mutex # @private - # @return [TracePoint] + # @sig TracePoint attr_reader :tracer # Asserts `cpath` corresponds to an explicit namespace for which `loader` # is responsible. # # @private - # @param cpath [String] - # @param loader [Zeitwerk::Loader] - # @return [void] + # @sig (String, Zeitwerk::Loader) -> void def register(cpath, loader) mutex.synchronize do cpaths[cpath] = loader @@ -42,19 +40,22 @@ module Zeitwerk end # @private - # @param loader [Zeitwerk::Loader] - # @return [void] + # @sig (Zeitwerk::Loader) -> void def unregister(loader) cpaths.delete_if { |_cpath, l| l == loader } disable_tracer_if_unneeded end + private + + # @sig () -> void def disable_tracer_if_unneeded mutex.synchronize do tracer.disable if cpaths.empty? end end + # @sig (TracePoint) -> void def tracepoint_class_callback(event) # If the class is a singleton class, we won't do anything with it so we # can bail out immediately. This is several orders of magnitude faster diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/gem_inflector.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/gem_inflector.rb similarity index 77% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/gem_inflector.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/gem_inflector.rb index e104fb9811..8e59de591a 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/gem_inflector.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/gem_inflector.rb @@ -2,16 +2,14 @@ module Zeitwerk class GemInflector < Inflector - # @param root_file [String] + # @sig (String) -> void def initialize(root_file) namespace = File.basename(root_file, ".rb") lib_dir = File.dirname(root_file) @version_file = File.join(lib_dir, namespace, "version.rb") end - # @param basename [String] - # @param abspath [String] - # @return [String] + # @sig (String, String) -> String def camelize(basename, abspath) abspath == @version_file ? "VERSION" : super end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/inflector.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/inflector.rb similarity index 87% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/inflector.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/inflector.rb index 4898376ccf..8cac2df0f2 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/inflector.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/inflector.rb @@ -11,9 +11,7 @@ module Zeitwerk # # Takes into account hard-coded mappings configured with `inflect`. # - # @param basename [String] - # @param _abspath [String] - # @return [String] + # @sig (String, String) -> String def camelize(basename, _abspath) overrides[basename] || basename.split('_').each(&:capitalize!).join end @@ -30,8 +28,7 @@ module Zeitwerk # inflector.camelize("mysql_adapter", abspath) # => "MySQLAdapter" # inflector.camelize("users_controller", abspath) # => "UsersController" # - # @param inflections [{String => String}] - # @return [void] + # @sig (Hash[String, String]) -> void def inflect(inflections) overrides.merge!(inflections) end @@ -41,7 +38,7 @@ module Zeitwerk # Hard-coded basename to constant name user maps that override the default # inflection logic. # - # @return [{String => String}] + # @sig () -> Hash[String, String] def overrides @overrides ||= {} end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/kernel.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/kernel.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/kernel.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/kernel.rb index 77ba0d70ca..79021dbe40 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/kernel.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/kernel.rb @@ -19,8 +19,7 @@ module Kernel # already existing ancestor chains. alias_method :zeitwerk_original_require, :require - # @param path [String] - # @return [Boolean] + # @sig (String) -> true | false def require(path) if loader = Zeitwerk::Registry.loader_for(path) if path.end_with?(".rb") diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/loader.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/loader.rb similarity index 87% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/loader.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/loader.rb index 4d0b5c252f..b63cbac222 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/loader.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/loader.rb @@ -9,13 +9,13 @@ module Zeitwerk include Callbacks include RealModName - # @return [String] + # @sig String attr_reader :tag - # @return [#camelize] + # @sig #camelize attr_accessor :inflector - # @return [#call, #debug, nil] + # @sig #call | #debug | nil attr_accessor :logger # Absolute paths of the root directories. Stored in a hash to preserve @@ -30,20 +30,20 @@ module Zeitwerk # interface for it is `push_dir` and `dirs`. # # @private - # @return [{String => true}] + # @sig Hash[String, true] attr_reader :root_dirs # Absolute paths of files or directories that have to be preloaded. # # @private - # @return [] + # @sig Array[String] attr_reader :preloads # Absolute paths of files, directories, or glob patterns to be totally # ignored. # # @private - # @return [Set] + # @sig Set[String] attr_reader :ignored_glob_patterns # The actual collection of absolute file and directory names at the time the @@ -51,20 +51,20 @@ module Zeitwerk # reload. # # @private - # @return [Set] + # @sig Set[String] attr_reader :ignored_paths # Absolute paths of directories or glob patterns to be collapsed. # # @private - # @return [Set] + # @sig Set[String] attr_reader :collapse_glob_patterns # The actual collection of absolute directory names at the time the collapse # glob patterns were expanded. Computed on setup, and recomputed on reload. # # @private - # @return [Set] + # @sig Set[String] attr_reader :collapse_dirs # Maps real absolute paths for which an autoload has been set ---and not @@ -76,7 +76,7 @@ module Zeitwerk # ... # # @private - # @return [{String => (Module, Symbol)}] + # @sig Hash[String, [Module, Symbol]] attr_reader :autoloads # We keep track of autoloaded directories to remove them from the registry @@ -86,7 +86,7 @@ module Zeitwerk # to concurrency (see why in Zeitwerk::Loader::Callbacks#on_dir_autoloaded). # # @private - # @return [] + # @sig Array[String] attr_reader :autoloaded_dirs # Stores metadata needed for unloading. Its entries look like this: @@ -102,7 +102,7 @@ module Zeitwerk # or eager loaded. Otherwise, the collection remains empty. # # @private - # @return [{String => (String, (Module, Symbol))}] + # @sig Hash[String, [String, [Module, Symbol]]] attr_reader :to_unload # Maps constant paths of namespaces to arrays of corresponding directories. @@ -120,21 +120,21 @@ module Zeitwerk # up the corresponding autoloads. # # @private - # @return [{String => }] + # @sig Hash[String, Array[String]] attr_reader :lazy_subdirs # Absolute paths of files or directories not to be eager loaded. # # @private - # @return [Set] + # @sig Set[String] attr_reader :eager_load_exclusions # @private - # @return [Mutex] + # @sig Mutex attr_reader :mutex # @private - # @return [Mutex] + # @sig Mutex attr_reader :mutex2 def initialize @@ -170,7 +170,7 @@ module Zeitwerk # Sets a tag for the loader, useful for logging. # # @param tag [#to_s] - # @return [void] + # @sig (#to_s) -> void def tag=(tag) @tag = tag.to_s end @@ -178,7 +178,7 @@ module Zeitwerk # Absolute paths of the root directories. This is a read-only collection, # please push here via `push_dir`. # - # @return [] + # @sig () -> Array[String] def dirs root_dirs.keys.freeze end @@ -189,10 +189,8 @@ module Zeitwerk # the same process already manages that directory or one of its ascendants # or descendants. # - # @param path [] - # @param namespace [Class, Module] # @raise [Zeitwerk::Error] - # @return [void] + # @sig (String | Pathname, Module) -> void def push_dir(path, namespace: Object) # Note that Class < Module. unless namespace.is_a?(Module) @@ -212,7 +210,7 @@ module Zeitwerk # There is no way to undo this, either you want to reload or you don't. # # @raise [Zeitwerk::Error] - # @return [void] + # @sig () -> void def enable_reloading mutex.synchronize do break if @reloading_enabled @@ -225,15 +223,14 @@ module Zeitwerk end end - # @return [Boolean] + # @sig () -> bool def reloading_enabled? @reloading_enabled end # Files or directories to be preloaded instead of lazy loaded. # - # @param paths [>] - # @return [void] + # @sig (*(String | Pathname | Array[String | Pathname])) -> void def preload(*paths) mutex.synchronize do expand_paths(paths).each do |abspath| @@ -245,8 +242,7 @@ module Zeitwerk # Configure files, directories, or glob patterns to be totally ignored. # - # @param paths [>] - # @return [void] + # @sig (*(String | Pathname | Array[String | Pathname])) -> void def ignore(*glob_patterns) glob_patterns = expand_paths(glob_patterns) mutex.synchronize do @@ -257,8 +253,7 @@ module Zeitwerk # Configure directories or glob patterns to be collapsed. # - # @param paths [>] - # @return [void] + # @sig (*(String | Pathname | Array[String | Pathname])) -> void def collapse(*glob_patterns) glob_patterns = expand_paths(glob_patterns) mutex.synchronize do @@ -269,7 +264,7 @@ module Zeitwerk # Sets autoloads in the root namespace and preloads files, if any. # - # @return [void] + # @sig () -> void def setup mutex.synchronize do break if @setup @@ -291,7 +286,7 @@ module Zeitwerk # unload them. # # @private - # @return [void] + # @sig () -> void def unload mutex.synchronize do # We are going to keep track of the files that were required by our @@ -354,7 +349,7 @@ module Zeitwerk # client code in the README of the project. # # @raise [Zeitwerk::Error] - # @return [void] + # @sig () -> void def reload if reloading_enabled? unload @@ -371,7 +366,7 @@ module Zeitwerk # are not eager loaded. You can opt-out specifically in specific files and # directories with `do_not_eager_load`. # - # @return [void] + # @sig () -> void def eager_load mutex.synchronize do break if @eager_loaded @@ -414,8 +409,7 @@ module Zeitwerk # Let eager load ignore the given files or directories. The constants # defined in those files are still autoloadable. # - # @param paths [>] - # @return [void] + # @sig (*(String | Pathname | Array[String | Pathname])) -> void def do_not_eager_load(*paths) mutex.synchronize { eager_load_exclusions.merge(expand_paths(paths)) } end @@ -423,8 +417,7 @@ module Zeitwerk # Says if the given constant path would be unloaded on reload. This # predicate returns `false` if reloading is disabled. # - # @param cpath [String] - # @return [Boolean] + # @sig (String) -> bool def unloadable_cpath?(cpath) to_unload.key?(cpath) end @@ -432,21 +425,20 @@ module Zeitwerk # Returns an array with the constant paths that would be unloaded on reload. # This predicate returns an empty array if reloading is disabled. # - # @return [] + # @sig () -> Array[String] def unloadable_cpaths to_unload.keys.freeze end # Logs to `$stdout`, handy shortcut for debugging. # - # @return [void] + # @sig () -> void def log! @logger = ->(msg) { puts msg } end # @private - # @param dir [String] - # @return [Boolean] + # @sig (String) -> bool def manages?(dir) dir = dir + "/" ignored_paths.each do |ignored_path| @@ -463,11 +455,11 @@ module Zeitwerk # --- Class methods --------------------------------------------------------------------------- class << self - # @return [#call, #debug, nil] + # @sig #call | #debug | nil attr_accessor :default_logger # @private - # @return [Mutex] + # @sig Mutex attr_accessor :mutex # This is a shortcut for @@ -481,7 +473,7 @@ module Zeitwerk # except that this method returns the same object in subsequent calls from # the same file, in the unlikely case the gem wants to be able to reload. # - # @return [Zeitwerk::Loader] + # @sig () -> Zeitwerk::Loader def for_gem called_from = caller_locations(1, 1).first.path Registry.loader_for_gem(called_from) @@ -489,7 +481,7 @@ module Zeitwerk # Broadcasts `eager_load` to all loaders. # - # @return [void] + # @sig () -> void def eager_load_all Registry.loaders.each(&:eager_load) end @@ -497,7 +489,7 @@ module Zeitwerk # Returns an array with the absolute paths of the root directories of all # registered loaders. This is a read-only collection. # - # @return [] + # @sig () -> Array[String] def all_dirs Registry.loaders.flat_map(&:dirs).freeze end @@ -507,16 +499,14 @@ module Zeitwerk private # ------------------------------------------------------------------------------------- - # @return [] + # @sig () -> Array[String] def actual_root_dirs root_dirs.reject do |root_dir, _namespace| !dir?(root_dir) || ignored_paths.member?(root_dir) end end - # @param dir [String] - # @param parent [Module] - # @return [void] + # @sig (String, Module) -> void def set_autoloads_in_dir(dir, parent) ls(dir) do |basename, abspath| begin @@ -559,10 +549,7 @@ module Zeitwerk end end - # @param parent [Module] - # @param cname [Symbol] - # @param subdir [String] - # @return [void] + # @sig (Module, Symbol, String) -> void def autoload_subdir(parent, cname, subdir) if autoload_path = autoload_for?(parent, cname) cpath = cpath(parent, cname) @@ -582,10 +569,7 @@ module Zeitwerk end end - # @param parent [Module] - # @param cname [Symbol] - # @param file [String] - # @return [void] + # @sig (Module, Symbol, String) -> void def autoload_file(parent, cname, file) if autoload_path = autoload_for?(parent, cname) # First autoload for a Ruby file wins, just ignore subsequent ones. @@ -606,11 +590,10 @@ module Zeitwerk end end - # @param dir [String] directory that would have autovivified a module - # @param file [String] the file where the namespace is explicitly defined - # @param parent [Module] - # @param cname [Symbol] - # @return [void] + # `dir` is the directory that would have autovivified a namespace. `file` is + # the file where we've found the namespace is explicitly defined. + # + # @sig (dir: String, file: String, parent: Module, cname: Symbol) -> void def promote_namespace_from_implicit_to_explicit(dir:, file:, parent:, cname:) autoloads.delete(dir) Registry.unregister_autoload(dir) @@ -619,10 +602,7 @@ module Zeitwerk register_explicit_namespace(cpath(parent, cname)) end - # @param parent [Module] - # @param cname [Symbol] - # @param abspath [String] - # @return [void] + # @sig (Module, Symbol, String) -> void def set_autoload(parent, cname, abspath) # $LOADED_FEATURES stores real paths since Ruby 2.4.4. We set and save the # real path to be able to delete it from $LOADED_FEATURES on unload, and to @@ -649,9 +629,7 @@ module Zeitwerk end end - # @param parent [Module] - # @param cname [Symbol] - # @return [String, nil] + # @sig (Module, Symbol) -> String? def autoload_for?(parent, cname) strict_autoload_path(parent, cname) || Registry.inception?(cpath(parent, cname)) end @@ -672,9 +650,7 @@ module Zeitwerk # # We need a way to strictly check in parent ignoring ancestors. # - # @param parent [Module] - # @param cname [Symbol] - # @return [String, nil] + # @sig (Module, Symbol) -> String? if method(:autoload?).arity == 1 def strict_autoload_path(parent, cname) parent.autoload?(cname) if cdef?(parent, cname) @@ -688,15 +664,14 @@ module Zeitwerk # This method is called this way because I prefer `preload` to be the method # name to configure preloads in the public interface. # - # @return [void] + # @sig () -> void def do_preload preloads.each do |abspath| do_preload_abspath(abspath) end end - # @param abspath [String] - # @return [void] + # @sig (String) -> void def do_preload_abspath(abspath) if ruby?(abspath) do_preload_file(abspath) @@ -705,31 +680,25 @@ module Zeitwerk end end - # @param dir [String] - # @return [void] + # @sig (String) -> void def do_preload_dir(dir) ls(dir) do |_basename, abspath| do_preload_abspath(abspath) end end - # @param file [String] - # @return [Boolean] + # @sig (String) -> bool def do_preload_file(file) log("preloading #{file}") if logger require file end - # @param parent [Module] - # @param cname [Symbol] - # @return [String] + # @sig (Module, Symbol) -> String def cpath(parent, cname) parent.equal?(Object) ? cname.to_s : "#{real_mod_name(parent)}::#{cname}" end - # @param dir [String] - # @yieldparam path [String, String] - # @return [void] + # @sig (String) { (String, String) -> void } -> void def ls(dir) Dir.foreach(dir) do |basename| next if basename.start_with?(".") @@ -743,57 +712,55 @@ module Zeitwerk end end - # @param path [String] - # @return [Boolean] + # @sig (String) -> bool def ruby?(path) path.end_with?(".rb") end - # @param path [String] - # @return [Boolean] + # @sig (String) -> bool def dir?(path) File.directory?(path) end - # @param paths [>] - # @return [] + # @sig (String | Pathname | Array[String | Pathname]) -> Array[String] def expand_paths(paths) paths.flatten.map! { |path| File.expand_path(path) } end - # @param glob_patterns [] - # @return [] + # @sig (Array[String]) -> Array[String] def expand_glob_patterns(glob_patterns) # Note that Dir.glob works with regular file names just fine. That is, # glob patterns technically need no wildcards. glob_patterns.flat_map { |glob_pattern| Dir.glob(glob_pattern) } end - # @return [void] + # @sig () -> void def recompute_ignored_paths ignored_paths.replace(expand_glob_patterns(ignored_glob_patterns)) end - # @return [void] + # @sig () -> void def recompute_collapse_dirs collapse_dirs.replace(expand_glob_patterns(collapse_glob_patterns)) end - # @param message [String] - # @return [void] + # @sig (String) -> void def log(message) method_name = logger.respond_to?(:debug) ? :debug : :call logger.send(method_name, "Zeitwerk@#{tag}: #{message}") end + # @sig (Module, Symbol) -> bool def cdef?(parent, cname) parent.const_defined?(cname, false) end + # @sig (String) -> void def register_explicit_namespace(cpath) ExplicitNamespace.register(cpath, self) end + # @sig (String) -> void def raise_if_conflicting_directory(dir) self.class.mutex.synchronize do Registry.loaders.each do |loader| @@ -808,19 +775,15 @@ module Zeitwerk end end - # @param parent [Module] - # @param cname [Symbol] - # @return [void] + # @sig (Module, Symbol) -> void def unload_autoload(parent, cname) - parent.send(:remove_const, cname) + parent.__send__(:remove_const, cname) log("autoload for #{cpath(parent, cname)} removed") if logger end - # @param parent [Module] - # @param cname [Symbol] - # @return [void] + # @sig (Module, Symbol) -> void def unload_cref(parent, cname) - parent.send(:remove_const, cname) + parent.__send__(:remove_const, cname) log("#{cpath(parent, cname)} unloaded") if logger end end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/loader/callbacks.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/loader/callbacks.rb similarity index 94% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/loader/callbacks.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/loader/callbacks.rb index 42cfdebc58..b929a71baf 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/loader/callbacks.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/loader/callbacks.rb @@ -4,8 +4,7 @@ module Zeitwerk::Loader::Callbacks # Invoked from our decorated Kernel#require when a managed file is autoloaded. # # @private - # @param file [String] - # @return [void] + # @sig (String) -> void def on_file_autoloaded(file) cref = autoloads.delete(file) to_unload[cpath(*cref)] = [file, cref] if reloading_enabled? @@ -22,8 +21,7 @@ module Zeitwerk::Loader::Callbacks # autoloaded. # # @private - # @param dir [String] - # @return [void] + # @sig (String) -> void def on_dir_autoloaded(dir) # Module#autoload does not serialize concurrent requires, and we handle # directories ourselves, so the callback needs to account for concurrency. @@ -59,8 +57,7 @@ module Zeitwerk::Loader::Callbacks # subdirectories, we descend into them now. # # @private - # @param namespace [Module] - # @return [void] + # @sig (Module) -> void def on_namespace_loaded(namespace) if subdirs = lazy_subdirs.delete(real_mod_name(namespace)) subdirs.each do |subdir| diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/real_mod_name.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/real_mod_name.rb similarity index 90% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/real_mod_name.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/real_mod_name.rb index cfd6c44fa7..c1233069b6 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/real_mod_name.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/real_mod_name.rb @@ -7,8 +7,7 @@ module Zeitwerk::RealModName # # The name method can be overridden, hence the indirection in this method. # - # @param mod [Class, Module] - # @return [String, nil] + # @sig (Module) -> String? if UnboundMethod.method_defined?(:bind_call) def real_mod_name(mod) UNBOUND_METHOD_MODULE_NAME.bind_call(mod) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/registry.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/registry.rb similarity index 82% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/registry.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/registry.rb index 3f8e1d43dd..dcb78dbe34 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/registry.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/registry.rb @@ -7,14 +7,14 @@ module Zeitwerk # them from being garbage collected. # # @private - # @return [] + # @sig Array[Zeitwerk::Loader] attr_reader :loaders # Registers loaders created with `for_gem` to make the method idempotent # in case of reload. # # @private - # @return [{String => Zeitwerk::Loader}] + # @sig Hash[String, Zeitwerk::Loader] attr_reader :loaders_managing_gems # Maps real paths to the loaders responsible for them. @@ -23,7 +23,7 @@ module Zeitwerk # invoke callbacks and autovivify modules. # # @private - # @return [{String => Zeitwerk::Loader}] + # @sig Hash[String, Zeitwerk::Loader] attr_reader :autoloads # This hash table addresses an edge case in which an autoload is ignored. @@ -62,14 +62,13 @@ module Zeitwerk # end # # @private - # @return [{String => (String, Zeitwerk::Loader)}] + # @sig Hash[String, [String, Zeitwerk::Loader]] attr_reader :inceptions # Registers a loader. # # @private - # @param loader [Zeitwerk::Loader] - # @return [void] + # @sig (Zeitwerk::Loader) -> void def register_loader(loader) loaders << loader end @@ -78,8 +77,7 @@ module Zeitwerk # file. That is how Zeitwerk::Loader.for_gem is idempotent. # # @private - # @param root_file [String] - # @return [Zeitwerk::Loader] + # @sig (String) -> Zeitwerk::Loader def loader_for_gem(root_file) loaders_managing_gems[root_file] ||= begin Loader.new.tap do |loader| @@ -91,32 +89,25 @@ module Zeitwerk end # @private - # @param loader [Zeitwerk::Loader] - # @param realpath [String] - # @return [void] + # @sig (Zeitwerk::Loader, String) -> String def register_autoload(loader, realpath) autoloads[realpath] = loader end # @private - # @param realpath [String] - # @return [void] + # @sig (String) -> void def unregister_autoload(realpath) autoloads.delete(realpath) end # @private - # @param cpath [String] - # @param realpath [String] - # @param loader [Zeitwerk::Loader] - # @return [void] + # @sig (String, String, Zeitwerk::Loader) -> void def register_inception(cpath, realpath, loader) inceptions[cpath] = [realpath, loader] end # @private - # @param cpath [String] - # @return [String, nil] + # @sig (String) -> String? def inception?(cpath) if pair = inceptions[cpath] pair.first @@ -124,15 +115,13 @@ module Zeitwerk end # @private - # @param path [String] - # @return [Zeitwerk::Loader, nil] + # @sig (String) -> Zeitwerk::Loader? def loader_for(path) autoloads[path] end # @private - # @param loader [Zeitwerk::Loader] - # @return [void] + # @sig (Zeitwerk::Loader) -> void def on_unload(loader) autoloads.delete_if { |_path, object| object == loader } inceptions.delete_if { |_cpath, (_path, object)| object == loader } diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/version.rb similarity index 71% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/version.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/version.rb index b62889cf79..4a5a3216ad 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.0/lib/zeitwerk/version.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/zeitwerk-2.4.1/lib/zeitwerk/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Zeitwerk - VERSION = "2.4.0" + VERSION = "2.4.1" end diff --git a/Library/Homebrew/version.rb b/Library/Homebrew/version.rb index 07ef21714c..8c1735e9a1 100644 --- a/Library/Homebrew/version.rb +++ b/Library/Homebrew/version.rb @@ -7,6 +7,8 @@ require "version/null" # # @api private class Version + extend T::Sig + include Comparable def self.formula_optionally_versioned_regex(name, full: true) @@ -15,6 +17,8 @@ class Version # A part of a {Version}. class Token + extend T::Sig + include Comparable def self.create(val) @@ -48,6 +52,7 @@ class Version @value = value end + sig { returns(String) } def inspect "#<#{self.class.name} #{value.inspect}>" end @@ -69,6 +74,7 @@ class Version end alias to_str to_s + sig { returns(T::Boolean) } def numeric? false end @@ -76,6 +82,8 @@ class Version # A pseudo-token representing the absence of a token. class NullToken < Token + extend T::Sig + def initialize super(nil) end @@ -95,10 +103,12 @@ class Version end end + sig { returns(T::Boolean) } def null? true end + sig { returns(String) } def inspect "#<#{self.class.name}>" end @@ -133,6 +143,7 @@ class Version # A token consisting of only numbers. class NumericToken < Token PATTERN = /[0-9]+/i.freeze + extend T::Sig def initialize(value) super @@ -153,6 +164,7 @@ class Version end end + sig { returns(T::Boolean) } def numeric? true end @@ -504,13 +516,11 @@ class Version l += 1 r += 1 next - elsif a.numeric? && b.numeric? - return a <=> b - elsif a.numeric? + elsif a.numeric? && !b.numeric? return 1 if a > NULL_TOKEN l += 1 - elsif b.numeric? + elsif !a.numeric? && b.numeric? return -1 if b > NULL_TOKEN r += 1 @@ -588,6 +598,8 @@ end # # @api private class HeadVersion < Version + extend T::Sig + attr_reader :commit def initialize(*) @@ -604,6 +616,7 @@ class HeadVersion < Version end end + sig { returns(T::Boolean) } def head? true end diff --git a/Library/Homebrew/version/null.rb b/Library/Homebrew/version/null.rb index f08d0765af..cf72179875 100644 --- a/Library/Homebrew/version/null.rb +++ b/Library/Homebrew/version/null.rb @@ -4,6 +4,8 @@ class Version # Represents the absence of a version. NULL = Class.new do + extend T::Sig + include Comparable def <=>(_other) @@ -18,19 +20,23 @@ class Version false end + sig { returns(T::Boolean) } def detected_from_url? false end + sig { returns(T::Boolean) } def head? false end + sig { returns(T::Boolean) } def null? true end # For {OS::Mac::Version} compatibility. + sig { returns(T::Boolean) } def requires_nehalem_cpu? false end @@ -51,27 +57,33 @@ class Version NULL_TOKEN end + sig { returns(Version) } def major_minor self end + sig { returns(Version) } def major_minor_patch self end + sig { returns(Float) } def to_f Float::NAN end + sig { returns(Integer) } def to_i 0 end + sig { returns(String) } def to_s "" end alias_method :to_str, :to_s + sig { returns(String) } def inspect "#" end diff --git a/docs/Adding-Software-to-Homebrew.md b/docs/Adding-Software-to-Homebrew.md index ded3bb891c..06099c0e42 100644 --- a/docs/Adding-Software-to-Homebrew.md +++ b/docs/Adding-Software-to-Homebrew.md @@ -19,7 +19,7 @@ If everything checks out, you're ready to get started on a new formula! 1. Try to install the formula using `brew install --build-from-source `, where \ is the name of your formula. If any errors occur, correct your formula and attempt to install it again. The formula should install without errors by the end of this step. -If you're stuck, ask for help on GitHub or [Discourse](https://discourse.brew.sh). The maintainers are very happy to help but we also like to see that you've put effort into trying to find a solution first. +If you're stuck, ask for help on GitHub or [Homebrew/discussions](https://github.com/homebrew/discussions/discussions). The maintainers are very happy to help but we also like to see that you've put effort into trying to find a solution first. ## Testing and auditing the formula diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 1f2636570b..584884075e 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -84,7 +84,7 @@ GEM html-pipeline (2.14.0) activesupport (>= 2) nokogiri (>= 1.4) - html-proofer (3.16.0) + html-proofer (3.17.0) addressable (~> 2.3) mercenary (~> 0.3) nokogumbo (~> 2.0) @@ -224,7 +224,7 @@ GEM octokit (4.18.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) - parallel (1.19.2) + parallel (1.20.0) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (3.1.1) diff --git a/docs/Homebrew-on-Linux.md b/docs/Homebrew-on-Linux.md index 6553846d5e..6dccb444eb 100644 --- a/docs/Homebrew-on-Linux.md +++ b/docs/Homebrew-on-Linux.md @@ -91,7 +91,7 @@ eval $(~/.linuxbrew/bin/brew shellenv) - [@HomebrewOnLinux on Twitter](https://twitter.com/HomebrewOnLinux) - [Homebrew/linuxbrew-core on GitHub](https://github.com/Homebrew/linuxbrew-core) -- [Homebrew on Linux category](https://discourse.brew.sh/c/linuxbrew) of [Homebrew's Discourse](https://discourse.brew.sh) +- [Homebrew/discussions (forum)](https://github.com/homebrew/discussions/discussions) ## Sponsors diff --git a/docs/Maintainer-Guidelines.md b/docs/Maintainer-Guidelines.md index 71c39d6266..93b1c219e6 100644 --- a/docs/Maintainer-Guidelines.md +++ b/docs/Maintainer-Guidelines.md @@ -174,8 +174,8 @@ The vast majority of Homebrew/homebrew-core PRs are bug fixes or version bumps s Maintainers have a variety of ways to communicate with each other: - Homebrew's public repositories on GitHub -- Homebrew's group communications between more than two maintainers on private channels (e.g. GitHub/Slack/Discourse) -- Homebrew's direct 1:1 messages between two maintainers on private channels (e.g. iMessage/Slack/Discourse/IRC/carrier pigeon) +- Homebrew's group communications between more than two maintainers on private channels (e.g. GitHub/Slack) +- Homebrew's direct 1:1 messages between two maintainers on private channels (e.g. iMessage/Slack/carrier pigeon) All communication should ideally occur in public on GitHub. Where this is not possible or appropriate (e.g. a security disclosure, interpersonal issue between two maintainers, urgent breakage that needs to be resolved) this can move to maintainers' private group communication and, if necessary, 1:1 communication. Technical decisions should not happen in 1:1 communications but if they do (or did in the past) they must end up back as something linkable on GitHub. For example, if a technical decision was made a year ago on Slack and another maintainer/contributor/user asks about it on GitHub, that's a good chance to explain it to them and have something that can be linked to in the future. diff --git a/docs/Manpage.md b/docs/Manpage.md index 4f3c8931a7..69a73fbb43 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1,5 +1,5 @@ -brew(1) -- The Missing Package Manager for macOS -================================================ +brew(1) -- The Missing Package Manager for macOS (or Linux) +=========================================================== ## SYNOPSIS @@ -9,34 +9,36 @@ brew(1) -- The Missing Package Manager for macOS ## DESCRIPTION Homebrew is the easiest and most flexible way to install the UNIX tools Apple -didn't include with macOS. +didn't include with macOS. It can also install software not packaged for your +Linux distribution to your home directory without requiring `sudo`. ## ESSENTIAL COMMANDS For the full command list, see the [COMMANDS](#commands) section. -With `--verbose` or `--debug`, many commands print extra debugging information. Note that -these options should only appear after a command. +With `--verbose` or `--debug`, many commands print extra debugging information. +Note that these options should only appear after a command. -### `install` *`formula`*: +### `install` *`formula`* Install *`formula`*. -*`formula`* is usually the name of the formula to install, but it has other syntaxes which -are listed in the [SPECIFYING FORMULAE](#specifying-formulae) section. +*`formula`* is usually the name of the formula to install, but it has other +syntaxes which are listed in the [SPECIFYING FORMULAE](#specifying-formulae) +section. -### `uninstall` *`formula`*: +### `uninstall` *`formula`* Uninstall *`formula`*. -### `list`: +### `list` List all installed formulae. -### `search` (*`text`*|`/`*`text`*`/`): +### `search` [*`text`*|`/`*`text`*`/`] -Perform a substring search of cask tokens and formula names for *`text`*. If *`text`* -is flanked by slashes, it is interpreted as a regular expression. +Perform a substring search of cask tokens and formula names for *`text`*. If +*`text`* is flanked by slashes, it is interpreted as a regular expression. The search for *`text`* is extended online to `homebrew/core` and `homebrew/cask`. If no search term is provided, all locally available formulae are listed. @@ -47,14 +49,14 @@ If no search term is provided, all locally available formulae are listed. Control Homebrew's anonymous aggregate user behaviour analytics. Read more at . -`brew analytics` [`state`]: -Display the current state of Homebrew's analytics. +`brew analytics` [`state`] +
Display the current state of Homebrew's analytics. -`brew analytics` [`on`|`off`]: -Turn Homebrew's analytics on or off respectively. +`brew analytics` (`on`|`off`) +
Turn Homebrew's analytics on or off respectively. -`brew analytics regenerate-uuid`: -Regenerate the UUID used for Homebrew's analytics. +`brew analytics regenerate-uuid` +
Regenerate the UUID used for Homebrew's analytics. ### `autoremove` [*`options`*] @@ -69,59 +71,38 @@ Homebrew Cask provides a friendly CLI workflow for the administration of macOS a Commands: -- `--cache` - Display the file used to cache a *`cask`* +- `audit` +
Check *`cask`* for Homebrew coding style violations. -- `audit` - Check *`cask`* for Homebrew coding style violations +- `cat` +
Dump raw source of a *`cask`* to the standard output. -- `cat` - Dump raw source of a *`cask`* to the standard output +- `create` +
Creates the given *`cask`* and opens it in an editor. -- `create` - Creates the given *`cask`* and opens it in an editor +- `edit` +
Open the given *`cask`* for editing. -- `doctor` - Checks for configuration issues +- `fetch` +
Downloads remote application files to local cache. -- `edit` - Open the given *`cask`* for editing +- `help` +
Print help for `cask` commands. -- `fetch` - Downloads remote application files to local cache +- `info` +
Displays information about the given *`cask`*. -- `help` - Print help for `cask` commands +- `install` +
Installs the given *`cask`*. -- `home` - Opens the homepage of the given *`cask`* +- `style` +
Checks style of the given *`cask`* using RuboCop. -- `info` - Displays information about the given *`cask`* +- `uninstall` +
Uninstalls the given *`cask`*. -- `install` - Installs the given *`cask`* - -- `list` - Lists installed casks or the casks provided in the arguments - -- `outdated` - List the outdated installed casks - -- `reinstall` - Reinstalls the given *`cask`* - -- `style` - Checks style of the given *`cask`* using RuboCop - -- `uninstall` - Uninstalls the given *`cask`* - -- `upgrade` - Upgrades all outdated casks or the specified casks - -- `zap` - Zaps all files associated with the given *`cask`* +- `zap` +
Zaps all files associated with the given *`cask`*. See also: `man brew` @@ -333,11 +314,11 @@ the installed formulae or, every 30 days, for all formulae. * `--cask`: Treat all named arguments as casks. * `--[no-]binaries`: - Disable/enable linking of helper executables. Default: enabled + Disable/enable linking of helper executables (default: enabled). * `--require-sha`: Require all casks to have a checksum. * `--[no-]quarantine`: - Disable/enable quarantining of downloads. Default: enabled + Disable/enable quarantining of downloads (default: enabled). * `--skip-cask-deps`: Skip installing cask dependencies. @@ -358,14 +339,14 @@ installations. * `-f`, `--force`: Allow keg-only formulae to be linked. -### `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. * `--formula`: - List only formulae. `This is the default action on non TTY.` + List only formulae. This is the default when output is not to a terminal. * `--cask`: List only casks, or *`cask`* if provided. * `--unbrewed`: @@ -443,9 +424,9 @@ information is displayed in interactive shells, and suppressed otherwise. * `-v`, `--verbose`: Include detailed version information. * `--formula`: - Only output outdated formulae. + List only outdated formulae. * `--cask`: - Only output outdated casks. + List only outdated casks. * `--json`: 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. v2 prints outdated formulae and casks. * `--fetch-HEAD`: @@ -503,11 +484,11 @@ reinstalled formulae or, every 30 days, for all formulae. * `--cask`: Treat all named arguments as casks. * `--[no-]binaries`: - Disable/enable linking of helper executables. Default: enabled + Disable/enable linking of helper executables (default: enabled). * `--require-sha`: Require all casks to have a checksum. * `--[no-]quarantine`: - Disable/enable quarantining of downloads. Default: enabled + Disable/enable quarantining of downloads (default: enabled). * `--skip-cask-deps`: Skip installing cask dependencies. @@ -527,7 +508,7 @@ No online search is performed. * `--desc`: Search for formulae with a description matching *`text`* and casks with a name matching *`text`*. * `--pull-request`: - Search for GitHub pull requests for *`text`*. + Search for GitHub pull requests containing *`text`*. * `--macports`: Search for *`text`* in the given package manager's list. * `--fink`: @@ -594,6 +575,10 @@ Uninstall *`formula`*. Delete all installed versions of *`formula`*. * `--ignore-dependencies`: Don't fail uninstall, even if *`formula`* is a dependency of any installed formulae. +* `--formula`: + Treat all named arguments as formulae. +* `--cask`: + Treat all named arguments as casks. ### `unlink` [*`options`*] *`formula`* @@ -666,11 +651,11 @@ upgraded formulae or, every 30 days, for all formulae. * `--cask`: Treat all named arguments as casks. If no named arguments are specified, upgrade only outdated casks. * `--[no-]binaries`: - Disable/enable linking of helper executables. Default: enabled + Disable/enable linking of helper executables (default: enabled). * `--require-sha`: Require all casks to have a checksum. * `--[no-]quarantine`: - Disable/enable quarantining of downloads. Default: enabled + Disable/enable quarantining of downloads (default: enabled). * `--skip-cask-deps`: Skip installing cask dependencies. * `--greedy`: @@ -696,7 +681,7 @@ specify *`formula`* as a required or recommended dependency for their stable bui * `--skip-recommended`: Skip all formulae that specify *`formula`* as `:recommended` type dependency. -### `--cache` [*`options`*] [*`formula|cask`*] +### `--cache` [*`options`*] [*`formula`*|*`cask`*] Display Homebrew's download cache. See also `HOMEBREW_CACHE`. @@ -759,12 +744,12 @@ Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homeb ## DEVELOPER COMMANDS -### `audit` [*`options`*] [*`formula`*] +### `audit` [*`options`*] [*`formula`*|*`cask`*] Check *`formula`* for Homebrew coding style violations. This should be run before -submitting a new formula. If no *`formula`* are provided, check all locally -available formulae and skip style checks. Will exit with a non-zero status if any -errors are found. +submitting a new formula or cask. If no *`formula`*|*`cask`* are provided, check all +locally available formulae and casks and skip style checks. Will exit with a +non-zero status if any errors are found. * `--strict`: Run additional, stricter style checks. @@ -772,8 +757,8 @@ errors are found. Run additional, slower style checks that navigate the Git repository. * `--online`: Run additional, slower style checks that require a network connection. -* `--new-formula`: - Run various additional style checks to determine if a new formula is eligible for Homebrew. This should be used when creating new formula and implies `--strict` and `--online`. +* `--new`: + Run various additional style checks to determine if a new formula or cask is eligible for Homebrew. This should be used when creating new formula and implies `--strict` and `--online`. * `--tap`: Check the formulae within the given tap, specified as *`user`*`/`*`repo`*. * `--fix`: @@ -783,7 +768,7 @@ errors are found. * `--display-filename`: Prefix every line of output with the file or formula name being audited, to make output easy to grep. * `--skip-style`: - Skip running non-RuboCop style checks. Useful if you plan on running `brew style` separately. Default unless a formula is specified by name + Skip running non-RuboCop style checks. Useful if you plan on running `brew style` separately. Enabled by default unless a formula is specified by name. * `-D`, `--audit-debug`: Enable debugging and profiling of audit methods. * `--only`: @@ -794,6 +779,14 @@ errors are found. Specify a comma-separated *`cops`* list to check for violations of only the listed RuboCop cops. * `--except-cops`: Specify a comma-separated *`cops`* list to skip checking for violations of the listed RuboCop cops. +* `--formula`: + Treat all named arguments as formulae. +* `--cask`: + Treat all named arguments as casks. +* `--[no-]appcast`: + Audit the appcast +* `--token-conflicts`: + Audit for token conflicts ### `bottle` [*`options`*] *`formula`* @@ -830,7 +823,7 @@ Also displays whether a pull request has been opened with the URL. * `--limit`: Limit number of package results returned. -### `bump-cask-pr` [*`options`*] [*`cask`*] +### `bump-cask-pr` [*`options`*] *`cask`* Create a pull request to update *`cask`* with a new version. @@ -914,7 +907,7 @@ nor vice versa. It must use whichever style specification the formula already us * `--revision`: Specify the new git commit *`revision`* corresponding to the specified *`tag`*. * `-f`, `--force`: - Ignore duplicate open PRs. Remove all mirrors if --mirror= was not specified. + Ignore duplicate open PRs. Remove all mirrors if `--mirror` was not specified. ### `bump-revision` [*`options`*] *`formula`* [*`formula`* ...] @@ -926,9 +919,14 @@ present, "revision 1" will be added. * `--message`: Append *`message`* to the default commit message. -### `cat` *`formula`* +### `cat` *`formula`*|*`cask`* -Display the source of *`formula`*. +Display the source of a *`formula`* or *`cask`*. + +* `--formula`: + Treat all named arguments as formulae. +* `--cask`: + Treat all named arguments as casks. ### `command` *`cmd`* @@ -975,7 +973,7 @@ a simple example. For the complete API, see: * `--tap`: Generate the new formula within the given tap, specified as *`user`*`/`*`repo`*. * `-f`, `--force`: - Ignore errors for disallowed formula names and named that shadow aliases. + Ignore errors for disallowed formula names and names that shadow aliases. ### `dispatch-build-bottle` [*`options`*] *`formula`* [*`formula`* ...] @@ -1090,7 +1088,7 @@ Find pull requests that can be automatically merged using `brew pr-publish`. * `--with-label`: Pull requests must have this label. * `--without-labels`: - Pull requests must not have these labels (default: `do not merge`, `new formula`, `automerge-skip`). + Pull requests must not have these labels (default: `do not merge`, `new formula`, `automerge-skip`, `linux-only`). * `--without-approval`: Pull requests do not require approval to be merged. * `--publish`: @@ -1237,11 +1235,11 @@ including core code and all formulae. Generate the template files for a new tap. * `--no-git`: - Don't initialize a git repository for the tap. + Don't initialize a Git repository for the tap. * `--pull-label`: - Label name for pull requests ready to be pulled (default `pr-pull`). + Label name for pull requests ready to be pulled (default: `pr-pull`). * `--branch`: - Initialize git repository with the specified branch name (default `main`). + Initialize Git repository with the specified branch name (default: `main`). ### `test` [*`options`*] *`formula`* @@ -1283,6 +1281,8 @@ Run Homebrew's unit and integration tests. Check for typechecking errors using Sorbet. +* `--fix`: + Automatically fix type errors. * `-q`, `--quiet`: Silence all non-critical errors. * `--update`: @@ -1348,54 +1348,57 @@ If no options are passed, use `origin/master` as the start commit. Install and commit Homebrew's vendored gems. +* `--update`: + Update all vendored Gems to the latest version. + ## GLOBAL CASK OPTIONS These options are applicable to subcommands accepting a `--cask` flag and all `cask` commands. -* `--appdir=`: - Target location for Applications. Default: `/Applications` +* `--appdir`: + Target location for Applications (default: `/Applications`). -* `--colorpickerdir=`: - Target location for Color Pickers. Default: `~/Library/ColorPickers` +* `--colorpickerdir`: + Target location for Color Pickers (default: `~/Library/ColorPickers`). -* `--prefpanedir=`: - Target location for Preference Panes. Default: `~/Library/PreferencePanes` +* `--prefpanedir`: + Target location for Preference Panes (default: `~/Library/PreferencePanes`). -* `--qlplugindir=`: - Target location for QuickLook Plugins. Default: `~/Library/QuickLook` +* `--qlplugindir`: + Target location for QuickLook Plugins (default: `~/Library/QuickLook`). -* `--mdimporterdir=`: - Target location for Spotlight Plugins. Default: `~/Library/Spotlight` +* `--mdimporterdir`: + Target location for Spotlight Plugins (default: `~/Library/Spotlight`). -* `--dictionarydir=`: - Target location for Dictionaries. Default: `~/Library/Dictionaries` +* `--dictionarydir`: + Target location for Dictionaries (default: `~/Library/Dictionaries`). -* `--fontdir=`: - Target location for Fonts. Default: `~/Library/Fonts` +* `--fontdir`: + Target location for Fonts (default: `~/Library/Fonts`). -* `--servicedir=`: - Target location for Services. Default: `~/Library/Services` +* `--servicedir`: + Target location for Services (default: `~/Library/Services`). -* `--input_methoddir=`: - Target location for Input Methods. Default: `~/Library/Input Methods` +* `--input_methoddir`: + Target location for Input Methods (default: `~/Library/Input Methods`). -* `--internet_plugindir=`: - Target location for Internet Plugins. Default: `~/Library/Internet Plug-Ins` +* `--internet_plugindir`: + Target location for Internet Plugins (default: `~/Library/Internet Plug-Ins`). -* `--audio_unit_plugindir=`: - Target location for Audio Unit Plugins. Default: `~/Library/Audio/Plug-Ins/Components` +* `--audio_unit_plugindir`: + Target location for Audio Unit Plugins (default: `~/Library/Audio/Plug-Ins/Components`). -* `--vst_plugindir=`: - Target location for VST Plugins. Default: `~/Library/Audio/Plug-Ins/VST` +* `--vst_plugindir`: + Target location for VST Plugins (default: `~/Library/Audio/Plug-Ins/VST`). -* `--vst3_plugindir=`: - Target location for VST3 Plugins. Default: `~/Library/Audio/Plug-Ins/VST3` +* `--vst3_plugindir`: + Target location for VST3 Plugins (default: `~/Library/Audio/Plug-Ins/VST3`). -* `--screen_saverdir=`: - Target location for Screen Savers. Default: `~/Library/Screen Savers` +* `--screen_saverdir`: + Target location for Screen Savers (default: `~/Library/Screen Savers`). * `--language`: - Set language of the Cask to install. The first matching language is used, otherwise the default language on the Cask. The default value is the `language of your system` + Comma-separated list of language codes to prefer for cask installation. The first matching language is used, otherwise it reverts to the cask's default language. The default value is the language of your system. ## GLOBAL OPTIONS @@ -1405,7 +1408,7 @@ These options are applicable across multiple subcommands. Display any debugging information. * `-q`, `--quiet`: - Suppress any warnings. + Make some output more quiet. * `-v`, `--verbose`: Make some output more verbose. @@ -1419,33 +1422,35 @@ These options are applicable across multiple subcommands. Bundler for non-Ruby dependencies from Homebrew, Homebrew Cask, Mac App Store and Whalebrew. -`brew bundle` [`install`]: -Install and upgrade (by default) all dependencies from the `Brewfile`. +`brew bundle` [`install`] +
Install and upgrade (by default) all dependencies from the `Brewfile`. -You can skip the installation of dependencies by adding space-separated values to one or more of the following environment variables: `HOMEBREW_BUNDLE_BREW_SKIP`, `HOMEBREW_BUNDLE_CASK_SKIP`, `HOMEBREW_BUNDLE_MAS_SKIP`, `HOMEBREW_BUNDLE_WHALEBREW_SKIP`, `HOMEBREW_BUNDLE_TAP_SKIP` +You can specify the `Brewfile` location using `--file` or by setting the `HOMEBREW_BUNDLE_FILE` environment variable. + +You can skip the installation of dependencies by adding space-separated values to one or more of the following environment variables: `HOMEBREW_BUNDLE_BREW_SKIP`, `HOMEBREW_BUNDLE_CASK_SKIP`, `HOMEBREW_BUNDLE_MAS_SKIP`, `HOMEBREW_BUNDLE_WHALEBREW_SKIP`, `HOMEBREW_BUNDLE_TAP_SKIP`. `brew bundle` will output a `Brewfile.lock.json` in the same directory as the `Brewfile` if all dependencies are installed successfully. This contains dependency and system status information which can be useful in debugging `brew bundle` failures and replicating a "last known good build" state. You can opt-out of this behaviour by setting the `HOMEBREW_BUNDLE_NO_LOCK` environment variable or passing the `--no-lock` option. You may wish to check this file into the same version control system as your `Brewfile` (or ensure your version control system ignores it if you'd prefer to rely on debugging information from a local machine). -`brew bundle dump`: -Write all installed casks/formulae/images/taps into a `Brewfile`. +`brew bundle dump` +
Write all installed casks/formulae/images/taps into a `Brewfile` in the current directory. -`brew bundle cleanup`: -Uninstall all dependencies not listed from the `Brewfile`. +`brew bundle cleanup` +
Uninstall all dependencies not listed from the `Brewfile`. This workflow is useful for maintainers or testers who regularly install lots of formulae. -`brew bundle check`: -Check if all dependencies are installed from the `Brewfile` . +`brew bundle check` +
Check if all dependencies are installed from the `Brewfile`. This provides a successful exit code if everything is up-to-date, making it useful for scripting. -`brew bundle list`: -List all dependencies present in a `Brewfile`. +`brew bundle list` +
List all dependencies present in the `Brewfile`. By default, only Homebrew dependencies are listed. -`brew bundle exec` *`command`*: -Run an external command in an isolated build environment based on the `Brewfile` dependencies. +`brew bundle exec` *`command`* +
Run an external command in an isolated build environment based on the `Brewfile` dependencies. This sanitized build environment ignores unrequested dependencies, which makes sure that things you didn't specify in your `Brewfile` won't get picked up by commands like `bundle install`, `npm install`, etc. It will also add compiler flags which will help find keg-only dependencies like `openssl`, `icu4c`, etc. @@ -1489,67 +1494,67 @@ Manage background services with macOS' `launchctl`(1) daemon manager. If `sudo` is passed, operate on `/Library/LaunchDaemons` (started at boot). Otherwise, operate on `~/Library/LaunchAgents` (started at login). -[`sudo`] `brew services` [`list`]: -List all managed services for the current user (or root). +[`sudo`] `brew services` [`list`] +
List all managed services for the current user (or root). -[`sudo`] `brew services run` (*`formula`*|`--all`): -Run the service *`formula`* without registering to launch at login (or boot). +[`sudo`] `brew services run` (*`formula`*|`--all`) +
Run the service *`formula`* without registering to launch at login (or boot). -[`sudo`] `brew services start` (*`formula`*|`--all`): -Start the service *`formula`* immediately and register it to launch at login (or boot). +[`sudo`] `brew services start` (*`formula`*|`--all`) +
Start the service *`formula`* immediately and register it to launch at login (or boot). -[`sudo`] `brew services stop` (*`formula`*|`--all`): -Stop the service *`formula`* immediately and unregister it from launching at login (or boot). +[`sudo`] `brew services stop` (*`formula`*|`--all`) +
Stop the service *`formula`* immediately and unregister it from launching at login (or boot). -[`sudo`] `brew services restart` (*`formula`*|`--all`): -Stop (if necessary) and start the service *`formula`* immediately and register it to launch at login (or boot). +[`sudo`] `brew services restart` (*`formula`*|`--all`) +
Stop (if necessary) and start the service *`formula`* immediately and register it to launch at login (or boot). -[`sudo`] `brew services cleanup`: -Remove all unused services. +[`sudo`] `brew services cleanup` +
Remove all unused services. * `--all`: Run *`subcommand`* on all services. -### `test-bot` [*`options`*] [*`formula`*]: +### `test-bot` [*`options`*] [*`formula`*] -Tests the full lifecycle of a Homebrew change to a tap (Git repository). For example, for a GitHub Actions pull request that changes a formula `brew test-bot` will ensure the system is cleaned and setup to test the formula, install the formula, run various tests and checks on it, bottle (package) the binaries and test formulae that depend on it to ensure they aren't broken by these changes. +Tests the full lifecycle of a Homebrew change to a tap (Git repository). For example, for a GitHub Actions pull request that changes a formula `brew test-bot` will ensure the system is cleaned and set up to test the formula, install the formula, run various tests and checks on it, bottle (package) the binaries and test formulae that depend on it to ensure they aren't broken by these changes. Only supports GitHub Actions as a CI provider. This is because Homebrew uses GitHub Actions and it's freely available for public and private use with macOS and Linux workers. * `--dry-run`: - print what would be done rather than doing it. + Print what would be done rather than doing it. * `--cleanup`: - clean all state from the Homebrew directory. Use with care! + Clean all state from the Homebrew directory. Use with care! * `--skip-setup`: - don't check if the local system is set up correctly. + Don't check if the local system is set up correctly. * `--keep-old`: - run `brew bottle --keep-old` to build new bottles for a single platform. + Run `brew bottle --keep-old` to build new bottles for a single platform. * `--skip-relocation`: - run `brew bottle --skip-relocation` to build new bottles that don't require relocation. + Run `brew bottle --skip-relocation` to build new bottles that don't require relocation. * `--local`: - ask Homebrew to write verbose logs under `./logs/` and set `$HOME` to `./home/` + Ask Homebrew to write verbose logs under `./logs/` and set `$HOME` to `./home/` * `--tap`: - use the `git` repository of the given tap. Defaults to the core tap for syntax checking. + Use the Git repository of the given tap. Defaults to the core tap for syntax checking. * `--fail-fast`: - immediately exit on a failing step. + Immediately exit on a failing step. * `-v`, `--verbose`: - print test step output in real time. Has the side effect of passing output as raw bytes instead of re-encoding in UTF-8. + Print test step output in real time. Has the side effect of passing output as raw bytes instead of re-encoding in UTF-8. * `--test-default-formula`: - use a default testing formula when not building a tap and no other formulae are specified. + Use a default testing formula when not building a tap and no other formulae are specified. * `--bintray-org`: - upload to the given Bintray organisation. + Upload bottles to the given Bintray organisation. * `--root-url`: - use the specified *`URL`* as the root of the bottle's URL instead of Homebrew's default. + Use the specified *`URL`* as the root of the bottle's URL instead of Homebrew's default. * `--git-name`: - set the Git author/committer names to the given name. + Set the Git author/committer names to the given name. * `--git-email`: - set the Git author/committer email to the given email. + Set the Git author/committer email to the given email. * `--ci-upload`: - use the Homebrew CI bottle upload options. + Use the Homebrew CI bottle upload options. * `--publish`: - publish the uploaded bottles. + Publish the uploaded bottles. * `--skip-recursive-dependents`: - only test the direct dependents. + Only test the direct dependents. * `--only-cleanup-before`: Only run the pre-cleanup step. Needs `--cleanup`. * `--only-setup`: @@ -1565,8 +1570,8 @@ Only supports GitHub Actions as a CI provider. This is because Homebrew uses Git Homebrew, like `git`(1), supports external commands. These are executable scripts that reside somewhere in the `PATH`, named `brew-`*`cmdname`* or -`brew-`*`cmdname`*`.rb`, which can be invoked like `brew` *`cmdname`*. This allows you -to create your own commands without modifying Homebrew's internals. +`brew-`*`cmdname`*`.rb`, which can be invoked like `brew` *`cmdname`*. This allows +you to create your own commands without modifying Homebrew's internals. Instructions for creating your own commands can be found in the docs: @@ -1597,252 +1602,251 @@ specified the same way as the *`formula`* arguments described in ## ENVIRONMENT -Note that environment variables must have a value set to be detected. For example, run -`export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just +Note that environment variables must have a value set to be detected. For +example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just `export HOMEBREW_NO_INSECURE_REDIRECT`. - * `HOMEBREW_ARCH`: - Linux only: Pass the set value to a type name representing the compiler's `-march` option. +- `HOMEBREW_ARCH` +
Linux only: Pass this value to a type name representing the compiler's `-march` option. - *Default:* `native`. + *Default:* `native`. - * `HOMEBREW_ARTIFACT_DOMAIN`: - Prefix all download URLs, including those for bottles, with this variable. For example, `HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080` will cause a formula with the URL `https://example.com/foo.tar.gz` to instead download from `http://localhost:8080/example.com/foo.tar.gz`. +- `HOMEBREW_ARTIFACT_DOMAIN` +
Prefix all download URLs, including those for bottles, with this variable. For example, `HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080` will cause a formula with the URL `https://example.com/foo.tar.gz` to instead download from `http://localhost:8080/example.com/foo.tar.gz`. - * `HOMEBREW_AUTO_UPDATE_SECS`: - Automatically check for updates once per this seconds interval. +- `HOMEBREW_AUTO_UPDATE_SECS` +
Automatically check for updates once per this seconds interval. - *Default:* `300`. + *Default:* `300`. - * `HOMEBREW_BAT`: - If set, use `bat` for the `brew cat` command. +- `HOMEBREW_BAT` +
If set, use `bat` for the `brew cat` command. - * `HOMEBREW_BAT_CONFIG_PATH`: - Use the `bat` configuration file. For example, `HOMEBREW_BAT=$HOME/.bat/config`. +- `HOMEBREW_BAT_CONFIG_PATH` +
Use this as the `bat` configuration file. - *Default:* $HOME/.bat/config + *Default:* `$HOME/.bat/config`. - * `HOMEBREW_BINTRAY_KEY`: - Use this API key when accessing the Bintray API (where bottles are stored). +- `HOMEBREW_BINTRAY_KEY` +
Use this API key when accessing the Bintray API (where bottles are stored). - * `HOMEBREW_BINTRAY_USER`: - Use this username when accessing the Bintray API (where bottles are stored). +- `HOMEBREW_BINTRAY_USER` +
Use this username when accessing the Bintray API (where bottles are stored). - * `HOMEBREW_BOTTLE_DOMAIN`: - Use the specified URL as the download mirror for bottles. For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to download from the prefix `http://localhost:8080/`. +- `HOMEBREW_BOTTLE_DOMAIN` +
Use this URL as the download mirror for bottles. For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to download from the prefix `http://localhost:8080/`. - *Default:* macOS: `https://homebrew.bintray.com/`, Linux: `https://linuxbrew.bintray.com/`. + *Default:* macOS: `https://homebrew.bintray.com/`, Linux: `https://linuxbrew.bintray.com/`. - * `HOMEBREW_BREW_GIT_REMOTE`: - Use the specified URL as the Homebrew/brew `git`(1) remote. +- `HOMEBREW_BREW_GIT_REMOTE` +
Use this URL as the Homebrew/brew `git`(1) remote. - *Default:* `https://github.com/Homebrew/brew`. + *Default:* `https://github.com/Homebrew/brew`. - * `HOMEBREW_BROWSER`: - Use this as the browser when opening project homepages. +- `HOMEBREW_BROWSER` +
Use this as the browser when opening project homepages. - *Default:* `$BROWSER` or the OS's default browser. + *Default:* `$BROWSER` or the OS's default browser. - * `HOMEBREW_CACHE`: - Use the specified directory as the download cache. +- `HOMEBREW_CACHE` +
Use this directory as the download cache. - *Default:* macOS: `$HOME/Library/Caches/Homebrew`, Linux: `$XDG_CACHE_HOME/Homebrew` or `$HOME/.cache/Homebrew`. + *Default:* macOS: `$HOME/Library/Caches/Homebrew`, Linux: `$XDG_CACHE_HOME/Homebrew` or `$HOME/.cache/Homebrew`. - * `HOMEBREW_CASK_OPTS`: - Options which should be used for all `cask` commands. All `--*dir` options, `--language`, `--require-sha`, `--no-quarantine` and `--no-binaries` are supported. -For example, you might add something like the following to your ~/.profile, ~/.bash_profile, or ~/.zshenv: +- `HOMEBREW_CASK_OPTS` +
Append these options to all `cask` commands. All `--*dir` options, `--language`, `--require-sha`, `--no-quarantine` and `--no-binaries` are supported. For example, you might add something like the following to your `~/.profile`, `~/.bash_profile`, or `~/.zshenv`: -`export HOMEBREW_CASK_OPTS='--appdir=~/Applications --fontdir=/Library/Fonts'` + `export HOMEBREW_CASK_OPTS="--appdir=~/Applications --fontdir=/Library/Fonts"` - * `HOMEBREW_CLEANUP_MAX_AGE_DAYS`: - Cleanup all cached files older than this many days. +- `HOMEBREW_CLEANUP_MAX_AGE_DAYS` +
Cleanup all cached files older than this many days. - *Default:* `120`. + *Default:* `120`. - * `HOMEBREW_COLOR`: - If set, force colour output on non-TTY outputs. +- `HOMEBREW_COLOR` +
If set, force colour output on non-TTY outputs. - * `HOMEBREW_CORE_GIT_REMOTE`: - Use the specified URL as the Homebrew/homebrew-core `git`(1) remote. +- `HOMEBREW_CORE_GIT_REMOTE` +
Use this URL as the Homebrew/homebrew-core `git`(1) remote. - *Default:* macOS: `https://github.com/Homebrew/homebrew-core`, Linux: `https://github.com/Homebrew/linuxbrew-core`. + *Default:* macOS: `https://github.com/Homebrew/homebrew-core`, Linux: `https://github.com/Homebrew/linuxbrew-core`. - * `HOMEBREW_CURLRC`: - If set, do not pass `--disable` when invoking `curl`(1), which disables the use of `curlrc`. +- `HOMEBREW_CURLRC` +
If set, do not pass `--disable` when invoking `curl`(1), which disables the use of `curlrc`. - * `HOMEBREW_CURL_RETRIES`: - Pass the given retry count to `--retry` when invoking `curl`(1). +- `HOMEBREW_CURL_RETRIES` +
Pass the given retry count to `--retry` when invoking `curl`(1). - *Default:* `3`. + *Default:* `3`. - * `HOMEBREW_CURL_VERBOSE`: - If set, pass `--verbose` when invoking `curl`(1). +- `HOMEBREW_CURL_VERBOSE` +
If set, pass `--verbose` when invoking `curl`(1). - * `HOMEBREW_DEVELOPER`: - If set, tweak behaviour to be more relevant for Homebrew developers (active or budding) by e.g. turning warnings into errors. +- `HOMEBREW_DEVELOPER` +
If set, tweak behaviour to be more relevant for Homebrew developers (active or budding) by e.g. turning warnings into errors. - * `HOMEBREW_DISABLE_LOAD_FORMULA`: - If set, refuse to load formulae. This is useful when formulae are not trusted (such as in pull requests). +- `HOMEBREW_DISABLE_LOAD_FORMULA` +
If set, refuse to load formulae. This is useful when formulae are not trusted (such as in pull requests). - * `HOMEBREW_DISPLAY`: - Use this X11 display when opening a page in a browser, for example with `brew home`. Primarily useful on Linux. +- `HOMEBREW_DISPLAY` +
Use this X11 display when opening a page in a browser, for example with `brew home`. Primarily useful on Linux. - *Default:* `$DISPLAY`. + *Default:* `$DISPLAY`. - * `HOMEBREW_DISPLAY_INSTALL_TIMES`: - If set, print install times for each formula at the end of the run. +- `HOMEBREW_DISPLAY_INSTALL_TIMES` +
If set, print install times for each formula at the end of the run. - * `HOMEBREW_EDITOR`: - Use this editor when editing a single formula, or several formulae in the same directory. +- `HOMEBREW_EDITOR` +
Use this editor when editing a single formula, or several formulae in the same directory. *Note:* `brew edit` will open all of Homebrew as discontinuous files and directories. Visual Studio Code can handle this correctly in project mode, but many editors will do strange things in this case. - *Default:* `$EDITOR` or `$VISUAL`. + *Default:* `$EDITOR` or `$VISUAL`. - * `HOMEBREW_FAIL_LOG_LINES`: - Output this many lines of output on formula `system` failures. +- `HOMEBREW_FAIL_LOG_LINES` +
Output this many lines of output on formula `system` failures. - *Default:* `15`. + *Default:* `15`. - * `HOMEBREW_FORBIDDEN_LICENSES`: - A space-separated list of licenses. Homebrew will refuse to install a formula if that formula or any of its dependencies has a license on this list. +- `HOMEBREW_FORBIDDEN_LICENSES` +
A space-separated list of licenses. Homebrew will refuse to install a formula if it or any of its dependencies has a license on this list. - * `HOMEBREW_FORCE_BREWED_CURL`: - If set, always use a Homebrew-installed `curl`(1) rather than the system version. Automatically set if the system version of `curl` is too old. +- `HOMEBREW_FORCE_BREWED_CURL` +
If set, always use a Homebrew-installed `curl`(1) rather than the system version. Automatically set if the system version of `curl` is too old. - * `HOMEBREW_FORCE_BREWED_GIT`: - If set, always use a Homebrew-installed `git`(1) rather than the system version. Automatically set if the system version of `git` is too old. +- `HOMEBREW_FORCE_BREWED_GIT` +
If set, always use a Homebrew-installed `git`(1) rather than the system version. Automatically set if the system version of `git` is too old. - * `HOMEBREW_FORCE_HOMEBREW_ON_LINUX`: - If set, running Homebrew on Linux will use URLs for macOS. This is useful when merging pull requests for macOS while on Linux. +- `HOMEBREW_FORCE_HOMEBREW_ON_LINUX` +
If set, running Homebrew on Linux will use URLs for macOS. This is useful when merging pull requests for macOS while on Linux. - * `HOMEBREW_FORCE_VENDOR_RUBY`: - If set, always use Homebrew's vendored, relocatable Ruby version even if the system version of Ruby is new enough. +- `HOMEBREW_FORCE_VENDOR_RUBY` +
If set, always use Homebrew's vendored, relocatable Ruby version even if the system version of Ruby is new enough. - * `HOMEBREW_GITHUB_API_PASSWORD`: - Use this password for authentication with the GitHub API, for features such as `brew search`. This is deprecated in favour of using `HOMEBREW_GITHUB_API_TOKEN`. +- `HOMEBREW_GITHUB_API_PASSWORD` +
Use this password for authentication with the GitHub API, for features such as `brew search`. This is deprecated in favour of using `HOMEBREW_GITHUB_API_TOKEN`. - * `HOMEBREW_GITHUB_API_TOKEN`: - Use this personal access token for the GitHub API, for features such as `brew search`. You can create one at . If set, GitHub will allow you a greater number of API requests. For more information, see: . +- `HOMEBREW_GITHUB_API_TOKEN` +
Use this personal access token for the GitHub API, for features such as `brew search`. You can create one at . If set, GitHub will allow you a greater number of API requests. For more information, see: *Note:* Homebrew doesn't require permissions for any of the scopes, but some developer commands may require additional permissions. - * `HOMEBREW_GITHUB_API_USERNAME`: - Use this username for authentication with the GitHub API, for features such as `brew search`. This is deprecated in favour of using `HOMEBREW_GITHUB_API_TOKEN`. +- `HOMEBREW_GITHUB_API_USERNAME` +
Use this username for authentication with the GitHub API, for features such as `brew search`. This is deprecated in favour of using `HOMEBREW_GITHUB_API_TOKEN`. - * `HOMEBREW_GIT_EMAIL`: - Set the Git author and committer name to this value. +- `HOMEBREW_GIT_EMAIL` +
Set the Git author and committer email to this value. - * `HOMEBREW_GIT_NAME`: - Set the Git author and committer email to this value. +- `HOMEBREW_GIT_NAME` +
Set the Git author and committer name to this value. - * `HOMEBREW_INSTALL_BADGE`: - Print this text before the installation summary of each successful build. +- `HOMEBREW_INSTALL_BADGE` +
Print this text before the installation summary of each successful build. - *Default:* The "Beer Mug" emoji. + *Default:* The "Beer Mug" emoji. - * `HOMEBREW_LIVECHECK_WATCHLIST`: - Use this file to get the list of default Formulae to check when no Formula argument is passed to `brew livecheck` +- `HOMEBREW_LIVECHECK_WATCHLIST` +
Consult this file for the list of formulae to check by default when no formula argument is passed to `brew livecheck`. - *Default:* `$HOME/.brew_livecheck_watchlist`. + *Default:* `$HOME/.brew_livecheck_watchlist`. - * `HOMEBREW_LOGS`: - Use the specified directory to store log files. +- `HOMEBREW_LOGS` +
Use this directory to store log files. - *Default:* macOS: `$HOME/Library/Logs/Homebrew`, Linux: `$XDG_CACHE_HOME/Homebrew/Logs` or `$HOME/.cache/Homebrew/Logs`. + *Default:* macOS: `$HOME/Library/Logs/Homebrew`, Linux: `$XDG_CACHE_HOME/Homebrew/Logs` or `$HOME/.cache/Homebrew/Logs`. - * `HOMEBREW_MAKE_JOBS`: - Use this value as the number of parallel jobs to run when building with `make`(1). +- `HOMEBREW_MAKE_JOBS` +
Use this value as the number of parallel jobs to run when building with `make`(1). - *Default:* The number of available CPU cores. + *Default:* The number of available CPU cores. - * `HOMEBREW_NO_ANALYTICS`: - If set, do not send analytics. See: . +- `HOMEBREW_NO_ANALYTICS` +
If set, do not send analytics. For more information, see: - * `HOMEBREW_NO_AUTO_UPDATE`: - If set, do not automatically update before running `brew install`, `brew upgrade` or `brew tap`. +- `HOMEBREW_NO_AUTO_UPDATE` +
If set, do not automatically update before running `brew install`, `brew upgrade` or `brew tap`. - * `HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK`: - If set, fail on the failure of installation from a bottle rather than falling back to building from source. +- `HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK` +
If set, fail on the failure of installation from a bottle rather than falling back to building from source. - * `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK`: - If set, do not check for broken dependents after installing, upgrading or reinstalling formulae. +- `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` +
If set, do not check for broken dependents after installing, upgrading or reinstalling formulae. - * `HOMEBREW_NO_COLOR`: - If set, do not print text with colour added. +- `HOMEBREW_NO_COLOR` +
If set, do not print text with colour added. - *Default:* `$NO_COLOR`. + *Default:* `$NO_COLOR`. - * `HOMEBREW_NO_COMPAT`: - If set, disable all use of legacy compatibility code. +- `HOMEBREW_NO_COMPAT` +
If set, disable all use of legacy compatibility code. - * `HOMEBREW_NO_EMOJI`: - If set, do not print `HOMEBREW_INSTALL_BADGE` on a successful build. +- `HOMEBREW_NO_EMOJI` +
If set, do not print `HOMEBREW_INSTALL_BADGE` on a successful build. - *Note:* Only tries to print emoji on OS X Lion or newer. + *Note:* Will only try to print emoji on OS X Lion or newer. - * `HOMEBREW_NO_GITHUB_API`: - If set, do not use the GitHub API, e.g. for searches or fetching relevant issues on a failed install. +- `HOMEBREW_NO_GITHUB_API` +
If set, do not use the GitHub API, e.g. for searches or fetching relevant issues after a failed install. - * `HOMEBREW_NO_INSECURE_REDIRECT`: - If set, forbid redirects from secure HTTPS to insecure HTTP. +- `HOMEBREW_NO_INSECURE_REDIRECT` +
If set, forbid redirects from secure HTTPS to insecure HTTP. - *Note:* While ensuring your downloads are fully secure, this is likely to cause from-source SourceForge, some GNU & GNOME based formulae to fail to download. + *Note:* While ensuring your downloads are fully secure, this is likely to cause from-source SourceForge, some GNU & GNOME-hosted formulae to fail to download. - * `HOMEBREW_NO_INSTALL_CLEANUP`: - If set, `brew install`, `brew upgrade` and `brew reinstall` will never automatically cleanup installed/upgraded/reinstalled formulae or all formulae every 30 days. +- `HOMEBREW_NO_INSTALL_CLEANUP` +
If set, `brew install`, `brew upgrade` and `brew reinstall` will never automatically cleanup installed/upgraded/reinstalled formulae or all formulae every 30 days. - * `HOMEBREW_PRY`: - If set, use Pry for the `brew irb` command. +- `HOMEBREW_PRY` +
If set, use Pry for the `brew irb` command. - * `HOMEBREW_SKIP_OR_LATER_BOTTLES`: - If set with `HOMEBREW_DEVELOPER`, do not use bottles from older versions of macOS. This is useful in development on new macOS versions. +- `HOMEBREW_SKIP_OR_LATER_BOTTLES` +
If set along with `HOMEBREW_DEVELOPER`, do not use bottles from older versions of macOS. This is useful in development on new macOS versions. - * `HOMEBREW_SORBET_RUNTIME`: - Enable runtime typechecking using Sorbet. +- `HOMEBREW_SORBET_RUNTIME` +
If set, enable runtime typechecking using Sorbet. - * `HOMEBREW_SVN`: - Use this as the `svn`(1) binary. +- `HOMEBREW_SVN` +
Use this as the `svn`(1) binary. - *Default:* A Homebrew-built Subversion (if installed), or the system-provided binary. + *Default:* A Homebrew-built Subversion (if installed), or the system-provided binary. - * `HOMEBREW_TEMP`: - Use this path as the temporary directory for building packages. Changing this may be needed if your system temporary directory and Homebrew prefix are on different volumes, as macOS has trouble moving symlinks across volumes when the target does not yet exist. This issue typically occurs when using FileVault or custom SSD configurations. +- `HOMEBREW_TEMP` +
Use this path as the temporary directory for building packages. Changing this may be needed if your system temporary directory and Homebrew prefix are on different volumes, as macOS has trouble moving symlinks across volumes when the target does not yet exist. This issue typically occurs when using FileVault or custom SSD configurations. - *Default:* macOS: `/private/tmp`, Linux: `/tmp`. + *Default:* macOS: `/private/tmp`, Linux: `/tmp`. - * `HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED`: - If set, `brew update` only outputs updates to installed software. +- `HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED` +
If set, `brew update` only lists updates to installed software. - * `HOMEBREW_UPDATE_TO_TAG`: - If set, always use the latest stable tag (even if developer commands have been run). +- `HOMEBREW_UPDATE_TO_TAG` +
If set, always use the latest stable tag (even if developer commands have been run). - * `HOMEBREW_VERBOSE`: - If set, always assume `--verbose` when running commands. +- `HOMEBREW_VERBOSE` +
If set, always assume `--verbose` when running commands. - * `HOMEBREW_DEBUG`: - If set, always assume `--debug` when running commands. +- `HOMEBREW_DEBUG` +
If set, always assume `--debug` when running commands. - * `HOMEBREW_VERBOSE_USING_DOTS`: - If set, verbose output will print a `.` no more than once a minute. This can be useful to avoid long-running Homebrew commands being killed due to no output. +- `HOMEBREW_VERBOSE_USING_DOTS` +
If set, verbose output will print a `.` no more than once a minute. This can be useful to avoid long-running Homebrew commands being killed due to no output. - * `all_proxy`: - Use this SOCKS5 proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. +- `all_proxy` +
Use this SOCKS5 proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. - * `ftp_proxy`: - Use this FTP proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. +- `ftp_proxy` +
Use this FTP proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. - * `http_proxy`: - Use this HTTP proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. +- `http_proxy` +
Use this HTTP proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. - * `https_proxy`: - Use this HTTPS proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. +- `https_proxy` +
Use this HTTPS proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. - * `no_proxy`: - A comma-separated list of hostnames and domain names excluded from proxying by `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. +- `no_proxy` +
A comma-separated list of hostnames and domain names excluded from proxying by `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew. - * `SUDO_ASKPASS`: - When this variable is set, the `-A` option is passed when calling `sudo`(8) +- `SUDO_ASKPASS` +
If set, pass the `-A` option when calling `sudo`(8). ## USING HOMEBREW BEHIND A PROXY @@ -1886,13 +1890,13 @@ Former maintainers with significant contributions include Jan Viljanen, JCount, See our issues on GitHub: * **Homebrew/brew**: - +
* **Homebrew/homebrew-core**: - +
* **Homebrew/homebrew-cask**: - +
[SYNOPSIS]: #SYNOPSIS "SYNOPSIS" [DESCRIPTION]: #DESCRIPTION "DESCRIPTION" diff --git a/docs/Releases.md b/docs/Releases.md index e62f6f095f..e427441469 100644 --- a/docs/Releases.md +++ b/docs/Releases.md @@ -8,7 +8,7 @@ Homebrew release: 1. Check the [Homebrew/brew pull requests](https://github.com/homebrew/brew/pulls), [issues](https://github.com/homebrew/brew/issues), [Homebrew/core issues](https://github.com/homebrew/homebrew-core/issues) and - [Discourse](https://discourse.brew.sh) to see if there is + [Homebrew/discussions (forum)](https://github.com/homebrew/discussions/discussions) to see if there is anything pressing that needs to be fixed or merged before the next release. If so, fix and merge these changes. 2. After no code changes have happened for at least a couple of hours (ideally 24 hours) diff --git a/docs/Tips-N'-Tricks.md b/docs/Tips-N'-Tricks.md index 098cd11c67..daa68d4eee 100644 --- a/docs/Tips-N'-Tricks.md +++ b/docs/Tips-N'-Tricks.md @@ -15,15 +15,6 @@ This can be useful if a package can't build against the version of something you And of course, you can simply `brew link ` again afterwards! -## Activate a previously installed version of a formula - -```sh -brew info -brew switch -``` - -Use `brew info ` to check what versions are installed but not currently activated, then `brew switch ` to activate the desired version. This can be useful if you would like to switch between versions of a formula. - ## Install into Homebrew without formulae ```sh diff --git a/docs/vale-styles/Homebrew/Titles.yml b/docs/vale-styles/Homebrew/Titles.yml index 2853a268f1..7f92482915 100644 --- a/docs/vale-styles/Homebrew/Titles.yml +++ b/docs/vale-styles/Homebrew/Titles.yml @@ -9,3 +9,4 @@ exceptions: - macOS - Homebrew/homebrew-core - Homebrew/linuxbrew-core + - (or Linux) diff --git a/manpages/brew.1 b/manpages/brew.1 index 1651219fa9..c9f6356510 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -4,7 +4,7 @@ .TH "BREW" "1" "November 2020" "Homebrew" "brew" . .SH "NAME" -\fBbrew\fR \- The Missing Package Manager for macOS +\fBbrew\fR \- The Missing Package Manager for macOS (or Linux) . .SH "SYNOPSIS" \fBbrew\fR \fB\-\-version\fR @@ -13,7 +13,7 @@ \fBbrew\fR \fIcommand\fR [\fB\-\-verbose\fR|\fB\-v\fR] [\fIoptions\fR] [\fIformula\fR] \.\.\. . .SH "DESCRIPTION" -Homebrew is the easiest and most flexible way to install the UNIX tools Apple didn\'t include with macOS\. +Homebrew is the easiest and most flexible way to install the UNIX tools Apple didn\'t include with macOS\. It can also install software not packaged for your Linux distribution to your home directory without requiring \fBsudo\fR\. . .SH "ESSENTIAL COMMANDS" For the full command list, see the \fICOMMANDS\fR section\. @@ -21,19 +21,19 @@ For the full command list, see the \fICOMMANDS\fR section\. .P With \fB\-\-verbose\fR or \fB\-\-debug\fR, many commands print extra debugging information\. Note that these options should only appear after a command\. . -.SS "\fBinstall\fR \fIformula\fR:" +.SS "\fBinstall\fR \fIformula\fR" Install \fIformula\fR\. . .P \fIformula\fR is usually the name of the formula to install, but it has other syntaxes which are listed in the \fISPECIFYING FORMULAE\fR section\. . -.SS "\fBuninstall\fR \fIformula\fR:" +.SS "\fBuninstall\fR \fIformula\fR" Uninstall \fIformula\fR\. . -.SS "\fBlist\fR:" +.SS "\fBlist\fR" List all installed formulae\. . -.SS "\fBsearch\fR (\fItext\fR|\fB/\fR\fItext\fR\fB/\fR):" +.SS "\fBsearch\fR [\fItext\fR|\fB/\fR\fItext\fR\fB/\fR]" Perform a substring search of cask tokens and formula names for \fItext\fR\. If \fItext\fR is flanked by slashes, it is interpreted as a regular expression\. The search for \fItext\fR is extended online to \fBhomebrew/core\fR and \fBhomebrew/cask\fR\. If no search term is provided, all locally available formulae are listed\. . .SH "COMMANDS" @@ -46,7 +46,7 @@ Control Homebrew\'s anonymous aggregate user behaviour analytics\. Read more at Display the current state of Homebrew\'s analytics\. . .P -\fBbrew analytics\fR [\fBon\fR|\fBoff\fR] +\fBbrew analytics\fR (\fBon\fR|\fBoff\fR) Turn Homebrew\'s analytics on or off respectively\. . .P @@ -66,115 +66,71 @@ Homebrew Cask provides a friendly CLI workflow for the administration of macOS a .P Commands: . -.IP "\(bu" 4 -\fB\-\-cache\fR -. -.br -Display the file used to cache a \fIcask\fR -. -.IP "\(bu" 4 +.TP \fBaudit\fR . .br -Check \fIcask\fR for Homebrew coding style violations +Check \fIcask\fR for Homebrew coding style violations\. . -.IP "\(bu" 4 +.TP \fBcat\fR . .br -Dump raw source of a \fIcask\fR to the standard output +Dump raw source of a \fIcask\fR to the standard output\. . -.IP "\(bu" 4 +.TP \fBcreate\fR . .br -Creates the given \fIcask\fR and opens it in an editor +Creates the given \fIcask\fR and opens it in an editor\. . -.IP "\(bu" 4 -\fBdoctor\fR -. -.br -Checks for configuration issues -. -.IP "\(bu" 4 +.TP \fBedit\fR . .br -Open the given \fIcask\fR for editing +Open the given \fIcask\fR for editing\. . -.IP "\(bu" 4 +.TP \fBfetch\fR . .br -Downloads remote application files to local cache +Downloads remote application files to local cache\. . -.IP "\(bu" 4 +.TP \fBhelp\fR . .br -Print help for \fBcask\fR commands +Print help for \fBcask\fR commands\. . -.IP "\(bu" 4 -\fBhome\fR -. -.br -Opens the homepage of the given \fIcask\fR -. -.IP "\(bu" 4 +.TP \fBinfo\fR . .br -Displays information about the given \fIcask\fR +Displays information about the given \fIcask\fR\. . -.IP "\(bu" 4 +.TP \fBinstall\fR . .br -Installs the given \fIcask\fR +Installs the given \fIcask\fR\. . -.IP "\(bu" 4 -\fBlist\fR -. -.br -Lists installed casks or the casks provided in the arguments -. -.IP "\(bu" 4 -\fBoutdated\fR -. -.br -List the outdated installed casks -. -.IP "\(bu" 4 -\fBreinstall\fR -. -.br -Reinstalls the given \fIcask\fR -. -.IP "\(bu" 4 +.TP \fBstyle\fR . .br -Checks style of the given \fIcask\fR using RuboCop +Checks style of the given \fIcask\fR using RuboCop\. . -.IP "\(bu" 4 +.TP \fBuninstall\fR . .br -Uninstalls the given \fIcask\fR +Uninstalls the given \fIcask\fR\. . -.IP "\(bu" 4 -\fBupgrade\fR -. -.br -Upgrades all outdated casks or the specified casks -. -.IP "\(bu" 4 +.TP \fBzap\fR . .br -Zaps all files associated with the given \fIcask\fR -. -.IP "" 0 +Zaps all files associated with the given \fIcask\fR\. . .P See also: \fBman brew\fR @@ -483,7 +439,7 @@ Treat all named arguments as casks\. . .TP \fB\-\-[no\-]binaries\fR -Disable/enable linking of helper executables\. Default: enabled +Disable/enable linking of helper executables (default: enabled)\. . .TP \fB\-\-require\-sha\fR @@ -491,7 +447,7 @@ Require all casks to have a checksum\. . .TP \fB\-\-[no\-]quarantine\fR -Disable/enable quarantining of downloads\. Default: enabled +Disable/enable quarantining of downloads (default: enabled)\. . .TP \fB\-\-skip\-cask\-deps\fR @@ -515,15 +471,15 @@ List files which would be linked or deleted by \fBbrew link \-\-overwrite\fR wit \fB\-f\fR, \fB\-\-force\fR Allow keg\-only formulae to be linked\. . -.SS "\fBlist\fR, \fBls\fR [\fIoptions\fR] [\fIformula|cask\fR]" -List all installed formulae or casks +.SS "\fBlist\fR, \fBls\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR]" +List all installed formulae and casks\. . .P If \fIformula\fR is provided, summarise the paths within its current keg\. . .TP \fB\-\-formula\fR -List only formulae\. \fBThis is the default action on non TTY\.\fR +List only formulae\. This is the default when output is not to a terminal\. . .TP \fB\-\-cask\fR @@ -634,11 +590,11 @@ Include detailed version information\. . .TP \fB\-\-formula\fR -Only output outdated formulae\. +List only outdated formulae\. . .TP \fB\-\-cask\fR -Only output outdated casks\. +List only outdated casks\. . .TP \fB\-\-json\fR @@ -717,7 +673,7 @@ Treat all named arguments as casks\. . .TP \fB\-\-[no\-]binaries\fR -Disable/enable linking of helper executables\. Default: enabled +Disable/enable linking of helper executables (default: enabled)\. . .TP \fB\-\-require\-sha\fR @@ -725,7 +681,7 @@ Require all casks to have a checksum\. . .TP \fB\-\-[no\-]quarantine\fR -Disable/enable quarantining of downloads\. Default: enabled +Disable/enable quarantining of downloads (default: enabled)\. . .TP \fB\-\-skip\-cask\-deps\fR @@ -751,7 +707,7 @@ Search for formulae with a description matching \fItext\fR and casks with a name . .TP \fB\-\-pull\-request\fR -Search for GitHub pull requests for \fItext\fR\. +Search for GitHub pull requests containing \fItext\fR\. . .TP \fB\-\-macports\fR @@ -840,6 +796,14 @@ Delete all installed versions of \fIformula\fR\. \fB\-\-ignore\-dependencies\fR Don\'t fail uninstall, even if \fIformula\fR is a dependency of any installed formulae\. . +.TP +\fB\-\-formula\fR +Treat all named arguments as formulae\. +. +.TP +\fB\-\-cask\fR +Treat all named arguments as casks\. +. .SS "\fBunlink\fR [\fIoptions\fR] \fIformula\fR" Remove symlinks for \fIformula\fR from Homebrew\'s prefix\. This can be useful for temporarily disabling a formula: \fBbrew unlink\fR \fIformula\fR \fB&&\fR \fIcommands\fR \fB&& brew link\fR \fIformula\fR . @@ -934,7 +898,7 @@ Treat all named arguments as casks\. If no named arguments are specified, upgrad . .TP \fB\-\-[no\-]binaries\fR -Disable/enable linking of helper executables\. Default: enabled +Disable/enable linking of helper executables (default: enabled)\. . .TP \fB\-\-require\-sha\fR @@ -942,7 +906,7 @@ Require all casks to have a checksum\. . .TP \fB\-\-[no\-]quarantine\fR -Disable/enable quarantining of downloads\. Default: enabled +Disable/enable quarantining of downloads (default: enabled)\. . .TP \fB\-\-skip\-cask\-deps\fR @@ -979,7 +943,7 @@ Include all formulae that specify \fIformula\fR as \fB:optional\fR type dependen \fB\-\-skip\-recommended\fR Skip all formulae that specify \fIformula\fR as \fB:recommended\fR type dependency\. . -.SS "\fB\-\-cache\fR [\fIoptions\fR] [\fIformula|cask\fR]" +.SS "\fB\-\-cache\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR]" Display Homebrew\'s download cache\. See also \fBHOMEBREW_CACHE\fR\. . .P @@ -1044,8 +1008,8 @@ Print the version numbers of Homebrew, Homebrew/homebrew\-core and Homebrew/home . .SH "DEVELOPER COMMANDS" . -.SS "\fBaudit\fR [\fIoptions\fR] [\fIformula\fR]" -Check \fIformula\fR for Homebrew coding style violations\. This should be run before submitting a new formula\. If no \fIformula\fR are provided, check all locally available formulae and skip style checks\. Will exit with a non\-zero status if any errors are found\. +.SS "\fBaudit\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR]" +Check \fIformula\fR for Homebrew coding style violations\. This should be run before submitting a new formula or cask\. If no \fIformula\fR|\fIcask\fR are provided, check all locally available formulae and casks and skip style checks\. Will exit with a non\-zero status if any errors are found\. . .TP \fB\-\-strict\fR @@ -1060,8 +1024,8 @@ Run additional, slower style checks that navigate the Git repository\. Run additional, slower style checks that require a network connection\. . .TP -\fB\-\-new\-formula\fR -Run various additional style checks to determine if a new formula is eligible for Homebrew\. This should be used when creating new formula and implies \fB\-\-strict\fR and \fB\-\-online\fR\. +\fB\-\-new\fR +Run various additional style checks to determine if a new formula or cask is eligible for Homebrew\. This should be used when creating new formula and implies \fB\-\-strict\fR and \fB\-\-online\fR\. . .TP \fB\-\-tap\fR @@ -1081,7 +1045,7 @@ Prefix every line of output with the file or formula name being audited, to make . .TP \fB\-\-skip\-style\fR -Skip running non\-RuboCop style checks\. Useful if you plan on running \fBbrew style\fR separately\. Default unless a formula is specified by name +Skip running non\-RuboCop style checks\. Useful if you plan on running \fBbrew style\fR separately\. Enabled by default unless a formula is specified by name\. . .TP \fB\-D\fR, \fB\-\-audit\-debug\fR @@ -1103,6 +1067,22 @@ Specify a comma\-separated \fIcops\fR list to check for violations of only the l \fB\-\-except\-cops\fR Specify a comma\-separated \fIcops\fR list to skip checking for violations of the listed RuboCop cops\. . +.TP +\fB\-\-formula\fR +Treat all named arguments as formulae\. +. +.TP +\fB\-\-cask\fR +Treat all named arguments as casks\. +. +.TP +\fB\-\-[no\-]appcast\fR +Audit the appcast +. +.TP +\fB\-\-token\-conflicts\fR +Audit for token conflicts +. .SS "\fBbottle\fR [\fIoptions\fR] \fIformula\fR" Generate a bottle (binary package) from a formula that was installed with \fB\-\-build\-bottle\fR\. If the formula specifies a rebuild version, it will be incremented in the generated DSL\. Passing \fB\-\-keep\-old\fR will attempt to keep it at its original value, while \fB\-\-no\-rebuild\fR will remove it\. . @@ -1149,7 +1129,7 @@ Display out\-of\-date brew formulae and the latest version available\. Also disp \fB\-\-limit\fR Limit number of package results returned\. . -.SS "\fBbump\-cask\-pr\fR [\fIoptions\fR] [\fIcask\fR]" +.SS "\fBbump\-cask\-pr\fR [\fIoptions\fR] \fIcask\fR" Create a pull request to update \fIcask\fR with a new version\. . .P @@ -1284,7 +1264,7 @@ Specify the new git commit \fIrevision\fR corresponding to the specified \fItag\ . .TP \fB\-f\fR, \fB\-\-force\fR -Ignore duplicate open PRs\. Remove all mirrors if \-\-mirror= was not specified\. +Ignore duplicate open PRs\. Remove all mirrors if \fB\-\-mirror\fR was not specified\. . .SS "\fBbump\-revision\fR [\fIoptions\fR] \fIformula\fR [\fIformula\fR \.\.\.]" Create a commit to increment the revision of \fIformula\fR\. If no revision is present, "revision 1" will be added\. @@ -1297,8 +1277,16 @@ Print what would be done rather than doing it\. \fB\-\-message\fR Append \fImessage\fR to the default commit message\. . -.SS "\fBcat\fR \fIformula\fR" -Display the source of \fIformula\fR\. +.SS "\fBcat\fR \fIformula\fR|\fIcask\fR" +Display the source of a \fIformula\fR or \fIcask\fR\. +. +.TP +\fB\-\-formula\fR +Treat all named arguments as formulae\. +. +.TP +\fB\-\-cask\fR +Treat all named arguments as casks\. . .SS "\fBcommand\fR \fIcmd\fR" Display the path to the file being used when invoking \fBbrew\fR \fIcmd\fR\. @@ -1372,7 +1360,7 @@ Generate the new formula within the given tap, specified as \fIuser\fR\fB/\fR\fI . .TP \fB\-f\fR, \fB\-\-force\fR -Ignore errors for disallowed formula names and named that shadow aliases\. +Ignore errors for disallowed formula names and names that shadow aliases\. . .SS "\fBdispatch\-build\-bottle\fR [\fIoptions\fR] \fIformula\fR [\fIformula\fR \.\.\.]" Build bottles for these formulae with GitHub Actions\. @@ -1512,7 +1500,7 @@ Pull requests must have this label\. . .TP \fB\-\-without\-labels\fR -Pull requests must not have these labels (default: \fBdo not merge\fR, \fBnew formula\fR, \fBautomerge\-skip\fR)\. +Pull requests must not have these labels (default: \fBdo not merge\fR, \fBnew formula\fR, \fBautomerge\-skip\fR, \fBlinux\-only\fR)\. . .TP \fB\-\-without\-approval\fR @@ -1713,15 +1701,15 @@ Generate the template files for a new tap\. . .TP \fB\-\-no\-git\fR -Don\'t initialize a git repository for the tap\. +Don\'t initialize a Git repository for the tap\. . .TP \fB\-\-pull\-label\fR -Label name for pull requests ready to be pulled (default \fBpr\-pull\fR)\. +Label name for pull requests ready to be pulled (default: \fBpr\-pull\fR)\. . .TP \fB\-\-branch\fR -Initialize git repository with the specified branch name (default \fBmain\fR)\. +Initialize Git repository with the specified branch name (default: \fBmain\fR)\. . .SS "\fBtest\fR [\fIoptions\fR] \fIformula\fR" Run the test method provided by an installed formula\. There is no standard output or return code, but generally it should notify the user if something is wrong with the installed formula\. @@ -1780,6 +1768,10 @@ Randomise tests with the specified \fIvalue\fR instead of a random seed\. Check for typechecking errors using Sorbet\. . .TP +\fB\-\-fix\fR +Automatically fix type errors\. +. +.TP \fB\-q\fR, \fB\-\-quiet\fR Silence all non\-critical errors\. . @@ -1870,68 +1862,72 @@ Use the commit at the specified \fIdate\fR as the start commit\. .SS "\fBvendor\-gems\fR" Install and commit Homebrew\'s vendored gems\. . +.TP +\fB\-\-update\fR +Update all vendored Gems to the latest version\. +. .SH "GLOBAL CASK OPTIONS" These options are applicable to subcommands accepting a \fB\-\-cask\fR flag and all \fBcask\fR commands\. . .TP -\fB\-\-appdir=\fR -Target location for Applications\. Default: \fB/Applications\fR +\fB\-\-appdir\fR +Target location for Applications (default: \fB/Applications\fR)\. . .TP -\fB\-\-colorpickerdir=\fR -Target location for Color Pickers\. Default: \fB~/Library/ColorPickers\fR +\fB\-\-colorpickerdir\fR +Target location for Color Pickers (default: \fB~/Library/ColorPickers\fR)\. . .TP -\fB\-\-prefpanedir=\fR -Target location for Preference Panes\. Default: \fB~/Library/PreferencePanes\fR +\fB\-\-prefpanedir\fR +Target location for Preference Panes (default: \fB~/Library/PreferencePanes\fR)\. . .TP -\fB\-\-qlplugindir=\fR -Target location for QuickLook Plugins\. Default: \fB~/Library/QuickLook\fR +\fB\-\-qlplugindir\fR +Target location for QuickLook Plugins (default: \fB~/Library/QuickLook\fR)\. . .TP -\fB\-\-mdimporterdir=\fR -Target location for Spotlight Plugins\. Default: \fB~/Library/Spotlight\fR +\fB\-\-mdimporterdir\fR +Target location for Spotlight Plugins (default: \fB~/Library/Spotlight\fR)\. . .TP -\fB\-\-dictionarydir=\fR -Target location for Dictionaries\. Default: \fB~/Library/Dictionaries\fR +\fB\-\-dictionarydir\fR +Target location for Dictionaries (default: \fB~/Library/Dictionaries\fR)\. . .TP -\fB\-\-fontdir=\fR -Target location for Fonts\. Default: \fB~/Library/Fonts\fR +\fB\-\-fontdir\fR +Target location for Fonts (default: \fB~/Library/Fonts\fR)\. . .TP -\fB\-\-servicedir=\fR -Target location for Services\. Default: \fB~/Library/Services\fR +\fB\-\-servicedir\fR +Target location for Services (default: \fB~/Library/Services\fR)\. . .TP -\fB\-\-input_methoddir=\fR -Target location for Input Methods\. Default: \fB~/Library/Input Methods\fR +\fB\-\-input_methoddir\fR +Target location for Input Methods (default: \fB~/Library/Input Methods\fR)\. . .TP -\fB\-\-internet_plugindir=\fR -Target location for Internet Plugins\. Default: \fB~/Library/Internet Plug\-Ins\fR +\fB\-\-internet_plugindir\fR +Target location for Internet Plugins (default: \fB~/Library/Internet Plug\-Ins\fR)\. . .TP -\fB\-\-audio_unit_plugindir=\fR -Target location for Audio Unit Plugins\. Default: \fB~/Library/Audio/Plug\-Ins/Components\fR +\fB\-\-audio_unit_plugindir\fR +Target location for Audio Unit Plugins (default: \fB~/Library/Audio/Plug\-Ins/Components\fR)\. . .TP -\fB\-\-vst_plugindir=\fR -Target location for VST Plugins\. Default: \fB~/Library/Audio/Plug\-Ins/VST\fR +\fB\-\-vst_plugindir\fR +Target location for VST Plugins (default: \fB~/Library/Audio/Plug\-Ins/VST\fR)\. . .TP -\fB\-\-vst3_plugindir=\fR -Target location for VST3 Plugins\. Default: \fB~/Library/Audio/Plug\-Ins/VST3\fR +\fB\-\-vst3_plugindir\fR +Target location for VST3 Plugins (default: \fB~/Library/Audio/Plug\-Ins/VST3\fR)\. . .TP -\fB\-\-screen_saverdir=\fR -Target location for Screen Savers\. Default: \fB~/Library/Screen Savers\fR +\fB\-\-screen_saverdir\fR +Target location for Screen Savers (default: \fB~/Library/Screen Savers\fR)\. . .TP \fB\-\-language\fR -Set language of the Cask to install\. The first matching language is used, otherwise the default language on the Cask\. The default value is the \fBlanguage of your system\fR +Comma\-separated list of language codes to prefer for cask installation\. The first matching language is used, otherwise it reverts to the cask\'s default language\. The default value is the language of your system\. . .SH "GLOBAL OPTIONS" These options are applicable across multiple subcommands\. @@ -1942,7 +1938,7 @@ Display any debugging information\. . .TP \fB\-q\fR, \fB\-\-quiet\fR -Suppress any warnings\. +Make some output more quiet\. . .TP \fB\-v\fR, \fB\-\-verbose\fR @@ -1962,14 +1958,17 @@ Bundler for non\-Ruby dependencies from Homebrew, Homebrew Cask, Mac App Store a Install and upgrade (by default) all dependencies from the \fBBrewfile\fR\. . .P -You can skip the installation of dependencies by adding space\-separated values to one or more of the following environment variables: \fBHOMEBREW_BUNDLE_BREW_SKIP\fR, \fBHOMEBREW_BUNDLE_CASK_SKIP\fR, \fBHOMEBREW_BUNDLE_MAS_SKIP\fR, \fBHOMEBREW_BUNDLE_WHALEBREW_SKIP\fR, \fBHOMEBREW_BUNDLE_TAP_SKIP\fR +You can specify the \fBBrewfile\fR location using \fB\-\-file\fR or by setting the \fBHOMEBREW_BUNDLE_FILE\fR environment variable\. +. +.P +You can skip the installation of dependencies by adding space\-separated values to one or more of the following environment variables: \fBHOMEBREW_BUNDLE_BREW_SKIP\fR, \fBHOMEBREW_BUNDLE_CASK_SKIP\fR, \fBHOMEBREW_BUNDLE_MAS_SKIP\fR, \fBHOMEBREW_BUNDLE_WHALEBREW_SKIP\fR, \fBHOMEBREW_BUNDLE_TAP_SKIP\fR\. . .P \fBbrew bundle\fR will output a \fBBrewfile\.lock\.json\fR in the same directory as the \fBBrewfile\fR if all dependencies are installed successfully\. This contains dependency and system status information which can be useful in debugging \fBbrew bundle\fR failures and replicating a "last known good build" state\. You can opt\-out of this behaviour by setting the \fBHOMEBREW_BUNDLE_NO_LOCK\fR environment variable or passing the \fB\-\-no\-lock\fR option\. You may wish to check this file into the same version control system as your \fBBrewfile\fR (or ensure your version control system ignores it if you\'d prefer to rely on debugging information from a local machine)\. . .P \fBbrew bundle dump\fR - Write all installed casks/formulae/images/taps into a \fBBrewfile\fR\. + Write all installed casks/formulae/images/taps into a \fBBrewfile\fR in the current directory\. . .P \fBbrew bundle cleanup\fR @@ -1980,14 +1979,14 @@ This workflow is useful for maintainers or testers who regularly install lots of . .P \fBbrew bundle check\fR - Check if all dependencies are installed from the \fBBrewfile\fR \. + Check if all dependencies are installed from the \fBBrewfile\fR\. . .P This provides a successful exit code if everything is up\-to\-date, making it useful for scripting\. . .P \fBbrew bundle list\fR - List all dependencies present in a \fBBrewfile\fR\. + List all dependencies present in the \fBBrewfile\fR\. . .P By default, only Homebrew dependencies are listed\. @@ -2097,79 +2096,79 @@ If \fBsudo\fR is passed, operate on \fB/Library/LaunchDaemons\fR (started at boo \fB\-\-all\fR Run \fIsubcommand\fR on all services\. . -.SS "\fBtest\-bot\fR [\fIoptions\fR] [\fIformula\fR]:" -Tests the full lifecycle of a Homebrew change to a tap (Git repository)\. For example, for a GitHub Actions pull request that changes a formula \fBbrew test\-bot\fR will ensure the system is cleaned and setup to test the formula, install the formula, run various tests and checks on it, bottle (package) the binaries and test formulae that depend on it to ensure they aren\'t broken by these changes\. +.SS "\fBtest\-bot\fR [\fIoptions\fR] [\fIformula\fR]" +Tests the full lifecycle of a Homebrew change to a tap (Git repository)\. For example, for a GitHub Actions pull request that changes a formula \fBbrew test\-bot\fR will ensure the system is cleaned and set up to test the formula, install the formula, run various tests and checks on it, bottle (package) the binaries and test formulae that depend on it to ensure they aren\'t broken by these changes\. . .P Only supports GitHub Actions as a CI provider\. This is because Homebrew uses GitHub Actions and it\'s freely available for public and private use with macOS and Linux workers\. . .TP \fB\-\-dry\-run\fR -print what would be done rather than doing it\. +Print what would be done rather than doing it\. . .TP \fB\-\-cleanup\fR -clean all state from the Homebrew directory\. Use with care! +Clean all state from the Homebrew directory\. Use with care! . .TP \fB\-\-skip\-setup\fR -don\'t check if the local system is set up correctly\. +Don\'t check if the local system is set up correctly\. . .TP \fB\-\-keep\-old\fR -run \fBbrew bottle \-\-keep\-old\fR to build new bottles for a single platform\. +Run \fBbrew bottle \-\-keep\-old\fR to build new bottles for a single platform\. . .TP \fB\-\-skip\-relocation\fR -run \fBbrew bottle \-\-skip\-relocation\fR to build new bottles that don\'t require relocation\. +Run \fBbrew bottle \-\-skip\-relocation\fR to build new bottles that don\'t require relocation\. . .TP \fB\-\-local\fR -ask Homebrew to write verbose logs under \fB\./logs/\fR and set \fB$HOME\fR to \fB\./home/\fR +Ask Homebrew to write verbose logs under \fB\./logs/\fR and set \fB$HOME\fR to \fB\./home/\fR . .TP \fB\-\-tap\fR -use the \fBgit\fR repository of the given tap\. Defaults to the core tap for syntax checking\. +Use the Git repository of the given tap\. Defaults to the core tap for syntax checking\. . .TP \fB\-\-fail\-fast\fR -immediately exit on a failing step\. +Immediately exit on a failing step\. . .TP \fB\-v\fR, \fB\-\-verbose\fR -print test step output in real time\. Has the side effect of passing output as raw bytes instead of re\-encoding in UTF\-8\. +Print test step output in real time\. Has the side effect of passing output as raw bytes instead of re\-encoding in UTF\-8\. . .TP \fB\-\-test\-default\-formula\fR -use a default testing formula when not building a tap and no other formulae are specified\. +Use a default testing formula when not building a tap and no other formulae are specified\. . .TP \fB\-\-bintray\-org\fR -upload to the given Bintray organisation\. +Upload bottles to the given Bintray organisation\. . .TP \fB\-\-root\-url\fR -use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew\'s default\. +Use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew\'s default\. . .TP \fB\-\-git\-name\fR -set the Git author/committer names to the given name\. +Set the Git author/committer names to the given name\. . .TP \fB\-\-git\-email\fR -set the Git author/committer email to the given email\. +Set the Git author/committer email to the given email\. . .TP \fB\-\-ci\-upload\fR -use the Homebrew CI bottle upload options\. +Use the Homebrew CI bottle upload options\. . .TP \fB\-\-publish\fR -publish the uploaded bottles\. +Publish the uploaded bottles\. . .TP \fB\-\-skip\-recursive\-dependents\fR -only test the direct dependents\. +Only test the direct dependents\. . .TP \fB\-\-only\-cleanup\-before\fR @@ -2220,17 +2219,23 @@ Note that environment variables must have a value set to be detected\. For examp . .TP \fBHOMEBREW_ARCH\fR -Linux only: Pass the set value to a type name representing the compiler\'s \fB\-march\fR option\. +. +.br +Linux only: Pass this value to a type name representing the compiler\'s \fB\-march\fR option\. . .IP \fIDefault:\fR \fBnative\fR\. . .TP \fBHOMEBREW_ARTIFACT_DOMAIN\fR +. +.br Prefix all download URLs, including those for bottles, with this variable\. For example, \fBHOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080\fR will cause a formula with the URL \fBhttps://example\.com/foo\.tar\.gz\fR to instead download from \fBhttp://localhost:8080/example\.com/foo\.tar\.gz\fR\. . .TP \fBHOMEBREW_AUTO_UPDATE_SECS\fR +. +.br Automatically check for updates once per this seconds interval\. . .IP @@ -2238,39 +2243,53 @@ Automatically check for updates once per this seconds interval\. . .TP \fBHOMEBREW_BAT\fR +. +.br If set, use \fBbat\fR for the \fBbrew cat\fR command\. . .TP \fBHOMEBREW_BAT_CONFIG_PATH\fR -Use the \fBbat\fR configuration file\. For example, \fBHOMEBREW_BAT=$HOME/\.bat/config\fR\. +. +.br +Use this as the \fBbat\fR configuration file\. . .IP -\fIDefault:\fR $HOME/\.bat/config +\fIDefault:\fR \fB$HOME/\.bat/config\fR\. . .TP \fBHOMEBREW_BINTRAY_KEY\fR +. +.br Use this API key when accessing the Bintray API (where bottles are stored)\. . .TP \fBHOMEBREW_BINTRAY_USER\fR +. +.br Use this username when accessing the Bintray API (where bottles are stored)\. . .TP \fBHOMEBREW_BOTTLE_DOMAIN\fR -Use the specified URL as the download mirror for bottles\. For example, \fBHOMEBREW_BOTTLE_DOMAIN=http://localhost:8080\fR will cause all bottles to download from the prefix \fBhttp://localhost:8080/\fR\. +. +.br +Use this URL as the download mirror for bottles\. For example, \fBHOMEBREW_BOTTLE_DOMAIN=http://localhost:8080\fR will cause all bottles to download from the prefix \fBhttp://localhost:8080/\fR\. . .IP \fIDefault:\fR macOS: \fBhttps://homebrew\.bintray\.com/\fR, Linux: \fBhttps://linuxbrew\.bintray\.com/\fR\. . .TP \fBHOMEBREW_BREW_GIT_REMOTE\fR -Use the specified URL as the Homebrew/brew \fBgit\fR(1) remote\. +. +.br +Use this URL as the Homebrew/brew \fBgit\fR(1) remote\. . .IP \fIDefault:\fR \fBhttps://github\.com/Homebrew/brew\fR\. . .TP \fBHOMEBREW_BROWSER\fR +. +.br Use this as the browser when opening project homepages\. . .IP @@ -2278,20 +2297,26 @@ Use this as the browser when opening project homepages\. . .TP \fBHOMEBREW_CACHE\fR -Use the specified directory as the download cache\. +. +.br +Use this directory as the download cache\. . .IP \fIDefault:\fR macOS: \fB$HOME/Library/Caches/Homebrew\fR, Linux: \fB$XDG_CACHE_HOME/Homebrew\fR or \fB$HOME/\.cache/Homebrew\fR\. . .TP \fBHOMEBREW_CASK_OPTS\fR -Options which should be used for all \fBcask\fR commands\. All \fB\-\-*dir\fR options, \fB\-\-language\fR, \fB\-\-require\-sha\fR, \fB\-\-no\-quarantine\fR and \fB\-\-no\-binaries\fR are supported\. For example, you might add something like the following to your ~/\.profile, ~/\.bash_profile, or ~/\.zshenv: . -.P -\fBexport HOMEBREW_CASK_OPTS=\'\-\-appdir=~/Applications \-\-fontdir=/Library/Fonts\'\fR +.br +Append these options to all \fBcask\fR commands\. All \fB\-\-*dir\fR options, \fB\-\-language\fR, \fB\-\-require\-sha\fR, \fB\-\-no\-quarantine\fR and \fB\-\-no\-binaries\fR are supported\. For example, you might add something like the following to your \fB~/\.profile\fR, \fB~/\.bash_profile\fR, or \fB~/\.zshenv\fR: +. +.IP +\fBexport HOMEBREW_CASK_OPTS="\-\-appdir=~/Applications \-\-fontdir=/Library/Fonts"\fR . .TP \fBHOMEBREW_CLEANUP_MAX_AGE_DAYS\fR +. +.br Cleanup all cached files older than this many days\. . .IP @@ -2299,21 +2324,29 @@ Cleanup all cached files older than this many days\. . .TP \fBHOMEBREW_COLOR\fR +. +.br If set, force colour output on non\-TTY outputs\. . .TP \fBHOMEBREW_CORE_GIT_REMOTE\fR -Use the specified URL as the Homebrew/homebrew\-core \fBgit\fR(1) remote\. +. +.br +Use this URL as the Homebrew/homebrew\-core \fBgit\fR(1) remote\. . .IP \fIDefault:\fR macOS: \fBhttps://github\.com/Homebrew/homebrew\-core\fR, Linux: \fBhttps://github\.com/Homebrew/linuxbrew\-core\fR\. . .TP \fBHOMEBREW_CURLRC\fR +. +.br If set, do not pass \fB\-\-disable\fR when invoking \fBcurl\fR(1), which disables the use of \fBcurlrc\fR\. . .TP \fBHOMEBREW_CURL_RETRIES\fR +. +.br Pass the given retry count to \fB\-\-retry\fR when invoking \fBcurl\fR(1)\. . .IP @@ -2321,18 +2354,26 @@ Pass the given retry count to \fB\-\-retry\fR when invoking \fBcurl\fR(1)\. . .TP \fBHOMEBREW_CURL_VERBOSE\fR +. +.br If set, pass \fB\-\-verbose\fR when invoking \fBcurl\fR(1)\. . .TP \fBHOMEBREW_DEVELOPER\fR +. +.br If set, tweak behaviour to be more relevant for Homebrew developers (active or budding) by e\.g\. turning warnings into errors\. . .TP \fBHOMEBREW_DISABLE_LOAD_FORMULA\fR +. +.br If set, refuse to load formulae\. This is useful when formulae are not trusted (such as in pull requests)\. . .TP \fBHOMEBREW_DISPLAY\fR +. +.br Use this X11 display when opening a page in a browser, for example with \fBbrew home\fR\. Primarily useful on Linux\. . .IP @@ -2340,10 +2381,14 @@ Use this X11 display when opening a page in a browser, for example with \fBbrew . .TP \fBHOMEBREW_DISPLAY_INSTALL_TIMES\fR +. +.br If set, print install times for each formula at the end of the run\. . .TP \fBHOMEBREW_EDITOR\fR +. +.br Use this editor when editing a single formula, or several formulae in the same directory\. . .IP @@ -2354,6 +2399,8 @@ Use this editor when editing a single formula, or several formulae in the same d . .TP \fBHOMEBREW_FAIL_LOG_LINES\fR +. +.br Output this many lines of output on formula \fBsystem\fR failures\. . .IP @@ -2361,49 +2408,71 @@ Output this many lines of output on formula \fBsystem\fR failures\. . .TP \fBHOMEBREW_FORBIDDEN_LICENSES\fR -A space\-separated list of licenses\. Homebrew will refuse to install a formula if that formula or any of its dependencies has a license on this list\. +. +.br +A space\-separated list of licenses\. Homebrew will refuse to install a formula if it or any of its dependencies has a license on this list\. . .TP \fBHOMEBREW_FORCE_BREWED_CURL\fR +. +.br If set, always use a Homebrew\-installed \fBcurl\fR(1) rather than the system version\. Automatically set if the system version of \fBcurl\fR is too old\. . .TP \fBHOMEBREW_FORCE_BREWED_GIT\fR +. +.br If set, always use a Homebrew\-installed \fBgit\fR(1) rather than the system version\. Automatically set if the system version of \fBgit\fR is too old\. . .TP \fBHOMEBREW_FORCE_HOMEBREW_ON_LINUX\fR +. +.br If set, running Homebrew on Linux will use URLs for macOS\. This is useful when merging pull requests for macOS while on Linux\. . .TP \fBHOMEBREW_FORCE_VENDOR_RUBY\fR +. +.br If set, always use Homebrew\'s vendored, relocatable Ruby version even if the system version of Ruby is new enough\. . .TP \fBHOMEBREW_GITHUB_API_PASSWORD\fR +. +.br Use this password for authentication with the GitHub API, for features such as \fBbrew search\fR\. This is deprecated in favour of using \fBHOMEBREW_GITHUB_API_TOKEN\fR\. . .TP \fBHOMEBREW_GITHUB_API_TOKEN\fR -Use this personal access token for the GitHub API, for features such as \fBbrew search\fR\. You can create one at \fIhttps://github\.com/settings/tokens\fR\. If set, GitHub will allow you a greater number of API requests\. For more information, see: \fIhttps://docs\.github\.com/en/rest/overview/resources\-in\-the\-rest\-api#rate\-limiting\fR\. +. +.br +Use this personal access token for the GitHub API, for features such as \fBbrew search\fR\. You can create one at \fIhttps://github\.com/settings/tokens\fR\. If set, GitHub will allow you a greater number of API requests\. For more information, see: \fIhttps://docs\.github\.com/en/rest/overview/resources\-in\-the\-rest\-api#rate\-limiting\fR . .IP \fINote:\fR Homebrew doesn\'t require permissions for any of the scopes, but some developer commands may require additional permissions\. . .TP \fBHOMEBREW_GITHUB_API_USERNAME\fR +. +.br Use this username for authentication with the GitHub API, for features such as \fBbrew search\fR\. This is deprecated in favour of using \fBHOMEBREW_GITHUB_API_TOKEN\fR\. . .TP \fBHOMEBREW_GIT_EMAIL\fR -Set the Git author and committer name to this value\. . -.TP -\fBHOMEBREW_GIT_NAME\fR +.br Set the Git author and committer email to this value\. . .TP +\fBHOMEBREW_GIT_NAME\fR +. +.br +Set the Git author and committer name to this value\. +. +.TP \fBHOMEBREW_INSTALL_BADGE\fR +. +.br Print this text before the installation summary of each successful build\. . .IP @@ -2411,20 +2480,26 @@ Print this text before the installation summary of each successful build\. . .TP \fBHOMEBREW_LIVECHECK_WATCHLIST\fR -Use this file to get the list of default Formulae to check when no Formula argument is passed to \fBbrew livecheck\fR +. +.br +Consult this file for the list of formulae to check by default when no formula argument is passed to \fBbrew livecheck\fR\. . .IP \fIDefault:\fR \fB$HOME/\.brew_livecheck_watchlist\fR\. . .TP \fBHOMEBREW_LOGS\fR -Use the specified directory to store log files\. +. +.br +Use this directory to store log files\. . .IP \fIDefault:\fR macOS: \fB$HOME/Library/Logs/Homebrew\fR, Linux: \fB$XDG_CACHE_HOME/Homebrew/Logs\fR or \fB$HOME/\.cache/Homebrew/Logs\fR\. . .TP \fBHOMEBREW_MAKE_JOBS\fR +. +.br Use this value as the number of parallel jobs to run when building with \fBmake\fR(1)\. . .IP @@ -2432,22 +2507,32 @@ Use this value as the number of parallel jobs to run when building with \fBmake\ . .TP \fBHOMEBREW_NO_ANALYTICS\fR -If set, do not send analytics\. See: \fIhttps://docs\.brew\.sh/Analytics\fR\. +. +.br +If set, do not send analytics\. For more information, see: \fIhttps://docs\.brew\.sh/Analytics\fR . .TP \fBHOMEBREW_NO_AUTO_UPDATE\fR +. +.br If set, do not automatically update before running \fBbrew install\fR, \fBbrew upgrade\fR or \fBbrew tap\fR\. . .TP \fBHOMEBREW_NO_BOTTLE_SOURCE_FALLBACK\fR +. +.br If set, fail on the failure of installation from a bottle rather than falling back to building from source\. . .TP \fBHOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK\fR +. +.br If set, do not check for broken dependents after installing, upgrading or reinstalling formulae\. . .TP \fBHOMEBREW_NO_COLOR\fR +. +.br If set, do not print text with colour added\. . .IP @@ -2455,44 +2540,62 @@ If set, do not print text with colour added\. . .TP \fBHOMEBREW_NO_COMPAT\fR +. +.br If set, disable all use of legacy compatibility code\. . .TP \fBHOMEBREW_NO_EMOJI\fR +. +.br If set, do not print \fBHOMEBREW_INSTALL_BADGE\fR on a successful build\. . .IP -\fINote:\fR Only tries to print emoji on OS X Lion or newer\. +\fINote:\fR Will only try to print emoji on OS X Lion or newer\. . .TP \fBHOMEBREW_NO_GITHUB_API\fR -If set, do not use the GitHub API, e\.g\. for searches or fetching relevant issues on a failed install\. +. +.br +If set, do not use the GitHub API, e\.g\. for searches or fetching relevant issues after a failed install\. . .TP \fBHOMEBREW_NO_INSECURE_REDIRECT\fR +. +.br If set, forbid redirects from secure HTTPS to insecure HTTP\. . .IP -\fINote:\fR While ensuring your downloads are fully secure, this is likely to cause from\-source SourceForge, some GNU & GNOME based formulae to fail to download\. +\fINote:\fR While ensuring your downloads are fully secure, this is likely to cause from\-source SourceForge, some GNU & GNOME\-hosted formulae to fail to download\. . .TP \fBHOMEBREW_NO_INSTALL_CLEANUP\fR +. +.br If set, \fBbrew install\fR, \fBbrew upgrade\fR and \fBbrew reinstall\fR will never automatically cleanup installed/upgraded/reinstalled formulae or all formulae every 30 days\. . .TP \fBHOMEBREW_PRY\fR +. +.br If set, use Pry for the \fBbrew irb\fR command\. . .TP \fBHOMEBREW_SKIP_OR_LATER_BOTTLES\fR -If set with \fBHOMEBREW_DEVELOPER\fR, do not use bottles from older versions of macOS\. This is useful in development on new macOS versions\. +. +.br +If set along with \fBHOMEBREW_DEVELOPER\fR, do not use bottles from older versions of macOS\. This is useful in development on new macOS versions\. . .TP \fBHOMEBREW_SORBET_RUNTIME\fR -Enable runtime typechecking using Sorbet\. +. +.br +If set, enable runtime typechecking using Sorbet\. . .TP \fBHOMEBREW_SVN\fR +. +.br Use this as the \fBsvn\fR(1) binary\. . .IP @@ -2500,6 +2603,8 @@ Use this as the \fBsvn\fR(1) binary\. . .TP \fBHOMEBREW_TEMP\fR +. +.br Use this path as the temporary directory for building packages\. Changing this may be needed if your system temporary directory and Homebrew prefix are on different volumes, as macOS has trouble moving symlinks across volumes when the target does not yet exist\. This issue typically occurs when using FileVault or custom SSD configurations\. . .IP @@ -2507,47 +2612,69 @@ Use this path as the temporary directory for building packages\. Changing this m . .TP \fBHOMEBREW_UPDATE_REPORT_ONLY_INSTALLED\fR -If set, \fBbrew update\fR only outputs updates to installed software\. +. +.br +If set, \fBbrew update\fR only lists updates to installed software\. . .TP \fBHOMEBREW_UPDATE_TO_TAG\fR +. +.br If set, always use the latest stable tag (even if developer commands have been run)\. . .TP \fBHOMEBREW_VERBOSE\fR +. +.br If set, always assume \fB\-\-verbose\fR when running commands\. . .TP \fBHOMEBREW_DEBUG\fR +. +.br If set, always assume \fB\-\-debug\fR when running commands\. . .TP \fBHOMEBREW_VERBOSE_USING_DOTS\fR +. +.br If set, verbose output will print a \fB\.\fR no more than once a minute\. This can be useful to avoid long\-running Homebrew commands being killed due to no output\. . .TP \fBall_proxy\fR +. +.br Use this SOCKS5 proxy for \fBcurl\fR(1), \fBgit\fR(1) and \fBsvn\fR(1) when downloading through Homebrew\. . .TP \fBftp_proxy\fR +. +.br Use this FTP proxy for \fBcurl\fR(1), \fBgit\fR(1) and \fBsvn\fR(1) when downloading through Homebrew\. . .TP \fBhttp_proxy\fR +. +.br Use this HTTP proxy for \fBcurl\fR(1), \fBgit\fR(1) and \fBsvn\fR(1) when downloading through Homebrew\. . .TP \fBhttps_proxy\fR +. +.br Use this HTTPS proxy for \fBcurl\fR(1), \fBgit\fR(1) and \fBsvn\fR(1) when downloading through Homebrew\. . .TP \fBno_proxy\fR +. +.br A comma\-separated list of hostnames and domain names excluded from proxying by \fBcurl\fR(1), \fBgit\fR(1) and \fBsvn\fR(1) when downloading through Homebrew\. . .TP \fBSUDO_ASKPASS\fR -When this variable is set, the \fB\-A\fR option is passed when calling \fBsudo\fR(8) +. +.br +If set, pass the \fB\-A\fR option when calling \fBsudo\fR(8)\. . .SH "USING HOMEBREW BEHIND A PROXY" Set the \fBhttp_proxy\fR, \fBhttps_proxy\fR, \fBall_proxy\fR, \fBftp_proxy\fR and/or \fBno_proxy\fR environment variables documented above\. @@ -2612,13 +2739,19 @@ See our issues on GitHub: . .TP \fBHomebrew/brew\fR +. +.br \fIhttps://github\.com/Homebrew/brew/issues\fR . .TP \fBHomebrew/homebrew\-core\fR +. +.br \fIhttps://github\.com/Homebrew/homebrew\-core/issues\fR . .TP \fBHomebrew/homebrew\-cask\fR +. +.br \fIhttps://github\.com/Homebrew/homebrew\-cask/issues\fR