diff --git a/Library/Homebrew/Gemfile b/Library/Homebrew/Gemfile index f13e5f3bbf..80ff8819be 100644 --- a/Library/Homebrew/Gemfile +++ b/Library/Homebrew/Gemfile @@ -21,6 +21,7 @@ gem "simplecov", require: false gem "sorbet", require: false gem "sorbet-runtime", require: false gem "tapioca", require: false +gem "warning", require: false # vendored gems gem "activesupport" diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index e2573ae3a2..841e67d3aa 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -163,6 +163,7 @@ GEM unf_ext unf_ext (0.0.7.7) unicode-display_width (2.0.0) + warning (1.1.0) webrick (1.7.0) webrobots (0.1.2) zeitwerk (2.4.2) @@ -200,6 +201,7 @@ DEPENDENCIES sorbet-runtime sorbet-runtime-stub tapioca + warning BUNDLED WITH 1.17.3 diff --git a/Library/Homebrew/style.rb b/Library/Homebrew/style.rb index 4e3b80942f..32a46a3471 100644 --- a/Library/Homebrew/style.rb +++ b/Library/Homebrew/style.rb @@ -72,6 +72,8 @@ module Homebrew end end + RUBOCOP = (HOMEBREW_LIBRARY_PATH/"utils/rubocop.rb").freeze + def run_rubocop(files, output_type, fix: false, except_cops: nil, only_cops: nil, display_cop_names: false, reset_cache: false, debug: false, verbose: false) @@ -134,11 +136,6 @@ module Homebrew FileUtils.rm_rf cache_env["XDG_CACHE_HOME"] if reset_cache - ruby_args = [ - "-S", - "rubocop", - ].compact.freeze - case output_type when :print args << "--debug" if debug @@ -149,11 +146,11 @@ module Homebrew args << "--color" if Tty.color? - system cache_env, RUBY_PATH, *ruby_args, *args + system cache_env, RUBY_PATH, RUBOCOP, *args $CHILD_STATUS.success? when :json result = system_command RUBY_PATH, - args: [*ruby_args, "--format", "json", *args], + args: [RUBOCOP, "--format", "json", *args], env: cache_env json = json_result!(result) json["files"] diff --git a/Library/Homebrew/utils/rubocop.rb b/Library/Homebrew/utils/rubocop.rb new file mode 100755 index 0000000000..92479fc410 --- /dev/null +++ b/Library/Homebrew/utils/rubocop.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby +# typed: false +# frozen_string_literal: true + +require "warning" + +warnings = [ + "warning: parser/current is loading parser/ruby26, which recognizes", + "warning: 2.6.6-compliant syntax, but you are running 2.6.3.", + "warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.", +] + +warnings.each do |warning| + Warning.ignore Regexp.new(warning) +end + +require "rubocop" + +exit RuboCop::CLI.new.run diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/warning-1.1.0/lib/warning.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/warning-1.1.0/lib/warning.rb new file mode 100644 index 0000000000..52177b3c5d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/warning-1.1.0/lib/warning.rb @@ -0,0 +1,248 @@ +require 'monitor' + +module Warning + module Processor + # Map of symbols to regexps for warning messages to ignore. + IGNORE_MAP = { + ambiguous_slash: /: warning: ambiguous first argument; put parentheses or a space even after `\/' operator\n\z/, + arg_prefix: /: warning: `[&\*]' interpreted as argument prefix\n\z/, + bignum: /: warning: constant ::Bignum is deprecated\n\z/, + fixnum: /: warning: constant ::Fixnum is deprecated\n\z/, + method_redefined: /: warning: method redefined; discarding old .+\n\z|: warning: previous definition of .+ was here\n\z/, + missing_gvar: /: warning: global variable `\$.+' not initialized\n\z/, + missing_ivar: /: warning: instance variable @.+ not initialized\n\z/, + not_reached: /: warning: statement not reached\n\z/, + shadow: /: warning: shadowing outer local variable - \w+\n\z/, + unused_var: /: warning: assigned but unused variable - \w+\n\z/, + useless_operator: /: warning: possibly useless use of [>method /regexp/ + # :bignum :: Ignore warnings when referencing the ::Bignum constant. + # :fixnum :: Ignore warnings when referencing the ::Fixnum constant. + # :keyword_separation :: Ignore warnings related to keyword argument separation. + # :method_redefined :: Ignore warnings when defining a method in a class/module where a + # method of the same name was already defined in that class/module. + # :missing_gvar :: Ignore warnings for accesses to global variables + # that have not yet been initialized + # :missing_ivar :: Ignore warnings for accesses to instance variables + # that have not yet been initialized + # :not_reached :: Ignore statement not reached warnings. + # :safe :: Ignore warnings related to $SAFE and related C-API functions. + # :shadow :: Ignore warnings related to shadowing outer local variables. + # :taint :: Ignore warnings related to taint and related methods and C-API functions. + # :unused_var :: Ignore warnings for unused variables. + # :useless_operator :: Ignore warnings when using operators such as == and > when the + # result is not used. + # + # Examples: + # + # # Ignore all uninitialized instance variable warnings + # Warning.ignore(/instance variable @\w+ not initialized/) + # + # # Ignore all uninitialized instance variable warnings in current file + # Warning.ignore(/instance variable @\w+ not initialized/, __FILE__) + # + # # Ignore all uninitialized instance variable warnings in current file + # Warning.ignore(:missing_ivar, __FILE__) + # + # # Ignore all uninitialized instance variable and method redefined warnings in current file + # Warning.ignore([:missing_ivar, :method_redefined], __FILE__) + def ignore(regexp, path='') + unless regexp = convert_regexp(regexp) + raise TypeError, "first argument to Warning.ignore should be Regexp, Symbol, or Array of Symbols, got #{regexp.inspect}" + end + + synchronize do + @ignore << [path, regexp] + end + nil + end + + # Handle all warnings starting with the given path, instead of + # the default behavior of printing them to $stderr. Examples: + # + # # Write warning to LOGGER at level warning + # Warning.process do |warning| + # LOGGER.warning(warning) + # end + # + # # Write warnings in the current file to LOGGER at level error level + # Warning.process(__FILE__) do |warning| + # LOGGER.error(warning) + # end + # + # The block can return one of the following symbols: + # + # :default :: Take the default action (call super, printing to $stderr). + # :backtrace :: Take the default action (call super, printing to $stderr), + # and also print the backtrace. + # :raise :: Raise a RuntimeError with the warning as the message. + # + # If the block returns anything else, it is assumed the block completely handled + # the warning and takes no other action. + # + # Instead of passing a block, you can pass a hash of actions to take for specific + # warnings, using regexp as keys and a callable objects as values: + # + # Warning.ignore(__FILE__, + # /instance variable @\w+ not initialized/ => proc do |warning| + # LOGGER.warning(warning) + # end, + # /global variable `\$\w+' not initialized/ => proc do |warning| + # LOGGER.error(warning) + # end + # ) + # + # Instead of passing a regexp as a key, you can pass a symbol that is recognized + # by Warning.ignore. Instead of passing a callable object as a value, you can + # pass a symbol, which will be treated as a callable object that returns that symbol: + # + # Warning.process(__FILE__, :missing_ivar=>:backtrace, :keyword_separation=>:raise) + def process(path='', actions=nil, &block) + if block + if actions + raise ArgumentError, "cannot pass both actions and block to Warning.process" + end + elsif actions + block = {} + actions.each do |regexp, value| + unless regexp = convert_regexp(regexp) + raise TypeError, "action provided to Warning.process should be Regexp, Symbol, or Array of Symbols, got #{regexp.inspect}" + end + + block[regexp] = ACTION_PROC_MAP[value] || value + end + else + raise ArgumentError, "must pass either actions or block to Warning.process" + end + + synchronize do + @process << [path, block] + @process.sort_by!(&:first) + @process.reverse! + end + nil + end + + # Handle ignored warnings and warning processors. If the warning is + # not ignored, is not a duplicate warning (if checking for duplicates) + # and there is no warning processor setup for the warning + # string, then use the default behavior of writing to $stderr. + def warn(str) + synchronize{@ignore.dup}.each do |path, regexp| + if str.start_with?(path) && str =~ regexp + return + end + end + + if @dedup + if synchronize{@dedup[str]} + return + end + + synchronize{@dedup[str] = true} + end + + action = catch(:action) do + synchronize{@process.dup}.each do |path, block| + if str.start_with?(path) + if block.is_a?(Hash) + block.each do |regexp, blk| + if str =~ regexp + throw :action, blk.call(str) + end + end + else + throw :action, block.call(str) + end + end + end + + :default + end + + case action + when :default + super + when :backtrace + super + $stderr.puts caller + when :raise + raise str + else + # nothing + end + + nil + end + + private + + # Convert the given Regexp, Symbol, or Array of Symbols into a Regexp. + def convert_regexp(regexp) + case regexp + when Regexp + regexp + when Symbol + IGNORE_MAP.fetch(regexp) + when Array + Regexp.union(regexp.map{|re| IGNORE_MAP.fetch(re)}) + else + # nothing + end + end + + def synchronize(&block) + @monitor.synchronize(&block) + end + end + + @ignore = [] + @process = [] + @dedup = false + @monitor = Monitor.new + + extend Processor +end