From 80a46edee487163cb853c6a4ab81e5b81dc54d77 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 01:23:07 -0500 Subject: [PATCH 01/15] tap: add style_exceptions configuration --- Library/Homebrew/rubocops/extend/formula.rb | 26 +++++++++++++++++++++ Library/Homebrew/tap.rb | 18 ++++++++++++++ Library/Homebrew/tap_auditor.rb | 4 +++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/rubocops/extend/formula.rb b/Library/Homebrew/rubocops/extend/formula.rb index 45e23a1b95..d3e75ea34f 100644 --- a/Library/Homebrew/rubocops/extend/formula.rb +++ b/Library/Homebrew/rubocops/extend/formula.rb @@ -35,6 +35,7 @@ module RuboCop class_node, parent_class_node, @body = *node @formula_name = Pathname.new(@file_path).basename(".rb").to_s + @tap_style_exceptions = nil audit_formula(node, class_node, parent_class_node, @body) end @@ -472,6 +473,31 @@ module RuboCop match_obj[1] end + # Returns whether the current formula exists in the given style exception list + def tap_style_exception?(list) + if @tap_style_exceptions.blank? && formula_tap.present? + @tap_style_exceptions = {} + + style_exceptions_dir = "#{File.dirname(File.dirname(@file_path))}/style_exceptions/*.json" + Pathname.glob(style_exceptions_dir).each do |exception_file| + list_name = exception_file.basename.to_s.chomp(".json").to_sym + list_contents = begin + JSON.parse exception_file.read + rescue JSON::ParserError + nil + end + next if list_contents.blank? + + @tap_style_exceptions[list_name] = list_contents + end + end + + return false if @tap_style_exceptions.blank? + return false unless @tap_style_exceptions.key? list + + @tap_style_exceptions[list].include? @formula_name + end + private def formula_class?(node) diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index c45f6d09a9..b2c87dccdc 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -21,12 +21,14 @@ class Tap HOMEBREW_TAP_FORMULA_RENAMES_FILE = "formula_renames.json" HOMEBREW_TAP_MIGRATIONS_FILE = "tap_migrations.json" HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions" + HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR = "style_exceptions" HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS = "pypi_formula_mappings.json" HOMEBREW_TAP_JSON_FILES = %W[ #{HOMEBREW_TAP_FORMULA_RENAMES_FILE} #{HOMEBREW_TAP_MIGRATIONS_FILE} #{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json + #{HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR}/*.json #{HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS} ].freeze @@ -114,6 +116,7 @@ class Tap @formula_renames = nil @tap_migrations = nil @audit_exceptions = nil + @style_exceptions = nil @pypi_formula_mappings = nil @config = nil remove_instance_variable(:@private) if instance_variable_defined?(:@private) @@ -567,6 +570,12 @@ class Tap @audit_exceptions = read_formula_list_directory "#{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*" end + # Hash with style exceptions + sig { returns(Hash) } + def style_exceptions + @style_exceptions = read_formula_list_directory "#{HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR}/*" + end + # Hash with pypi formula mappings sig { returns(Hash) } def pypi_formula_mappings @@ -760,6 +769,15 @@ class CoreTap < Tap end end + # @private + def style_exceptions + @style_exceptions ||= begin + self.class.ensure_installed! + super + end + end + + # @private def pypi_formula_mappings @pypi_formula_mappings ||= begin self.class.ensure_installed! diff --git a/Library/Homebrew/tap_auditor.rb b/Library/Homebrew/tap_auditor.rb index 5936980919..aa08ace9e7 100644 --- a/Library/Homebrew/tap_auditor.rb +++ b/Library/Homebrew/tap_auditor.rb @@ -8,13 +8,14 @@ module Homebrew class TapAuditor extend T::Sig - attr_reader :name, :path, :tap_audit_exceptions, :tap_pypi_formula_mappings, :problems + attr_reader :name, :path, :tap_audit_exceptions, :tap_style_exceptions, :tap_pypi_formula_mappings, :problems sig { params(tap: Tap, strict: T.nilable(T::Boolean)).void } def initialize(tap, strict:) @name = tap.name @path = tap.path @tap_audit_exceptions = tap.audit_exceptions + @tap_style_exceptions = tap.style_exceptions @tap_pypi_formula_mappings = tap.pypi_formula_mappings @problems = [] end @@ -38,6 +39,7 @@ module Homebrew sig { void } def audit_tap_formula_lists check_formula_list_directory "audit_exceptions", @tap_audit_exceptions + check_formula_list_directory "style_exceptions", @tap_style_exceptions check_formula_list "pypi_formula_mappings", @tap_pypi_formula_mappings end From e823dd713e015894fec563b08318ca5d009f6cf5 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 01:23:19 -0500 Subject: [PATCH 02/15] Migrate VERSIONED_FORMULAE_CONFLICTS_ALLOWLIST --- Library/Homebrew/rubocops/conflicts.rb | 6 +----- Library/Homebrew/test/rubocops/conflicts_spec.rb | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Library/Homebrew/rubocops/conflicts.rb b/Library/Homebrew/rubocops/conflicts.rb index 7a24be5ce1..dd8e524e14 100644 --- a/Library/Homebrew/rubocops/conflicts.rb +++ b/Library/Homebrew/rubocops/conflicts.rb @@ -12,10 +12,6 @@ module RuboCop MSG = "Versioned formulae should not use `conflicts_with`. " \ "Use `keg_only :versioned_formula` instead." - ALLOWLIST = %w[ - bash-completion@2 - ].freeze - def audit_formula(_node, _class_node, _parent_class_node, body_node) find_method_calls_by_name(body_node, :conflicts_with).each do |conflicts_with_call| next unless parameters(conflicts_with_call).last.respond_to? :values @@ -35,7 +31,7 @@ module RuboCop return unless versioned_formula? - problem MSG if !ALLOWLIST.include?(@formula_name) && + problem MSG if !tap_style_exception?(:versioned_formulae_conflicts_allowlist) && method_called_ever?(body_node, :conflicts_with) end diff --git a/Library/Homebrew/test/rubocops/conflicts_spec.rb b/Library/Homebrew/test/rubocops/conflicts_spec.rb index 3d2fe41462..b853af3329 100644 --- a/Library/Homebrew/test/rubocops/conflicts_spec.rb +++ b/Library/Homebrew/test/rubocops/conflicts_spec.rb @@ -85,6 +85,4 @@ describe RuboCop::Cop::FormulaAudit::Conflicts do expect(new_source).to eq(corrected_source) end end - - include_examples "formulae exist", described_class::ALLOWLIST end From 629ad219aaae2bb7c3db03ed526734f1dffb9e6d Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 01:31:14 -0500 Subject: [PATCH 03/15] Migrate MAKE_CHECK_ALLOWLIST --- Library/Homebrew/rubocops/lines.rb | 22 +------------------- Library/Homebrew/test/rubocops/lines_spec.rb | 2 -- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/Library/Homebrew/rubocops/lines.rb b/Library/Homebrew/rubocops/lines.rb index ad5c700736..31b78a50db 100644 --- a/Library/Homebrew/rubocops/lines.rb +++ b/Library/Homebrew/rubocops/lines.rb @@ -623,33 +623,13 @@ module RuboCop # # @api private class MakeCheck < FormulaCop - MAKE_CHECK_ALLOWLIST = %w[ - beecrypt - ccrypt - git - gmp - gnupg - gnupg@1.4 - google-sparsehash - jemalloc - jpeg-turbo - mpfr - nettle - open-mpi - openssl@1.1 - pcre - protobuf - wolfssl - xz - ].freeze - def audit_formula(_node, _class_node, _parent_class_node, body_node) return if formula_tap != "homebrew-core" # Avoid build-time checks in homebrew/core find_every_method_call_by_name(body_node, :system).each do |method| next if @formula_name.start_with?("lib") - next if MAKE_CHECK_ALLOWLIST.include?(@formula_name) + next if tap_style_exception? :make_check_allowlist params = parameters(method) next unless node_equals?(params[0], "make") diff --git a/Library/Homebrew/test/rubocops/lines_spec.rb b/Library/Homebrew/test/rubocops/lines_spec.rb index 610670ee13..3cb2eade4e 100644 --- a/Library/Homebrew/test/rubocops/lines_spec.rb +++ b/Library/Homebrew/test/rubocops/lines_spec.rb @@ -1479,8 +1479,6 @@ describe RuboCop::Cop::FormulaAuditStrict::MakeCheck do end RUBY end - - include_examples "formulae exist", described_class::MAKE_CHECK_ALLOWLIST end describe RuboCop::Cop::FormulaAuditStrict::ShellCommands do From 1dbbcfd1d603e829e4652323c34c2a1d54efca8a Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 12:29:38 -0500 Subject: [PATCH 04/15] Migrate COMPONENTS_ORDER_EXCEPTIONS --- Library/Homebrew/rubocops/components_order.rb | 7 +------ Library/Homebrew/test/rubocops/components_order_spec.rb | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Library/Homebrew/rubocops/components_order.rb b/Library/Homebrew/rubocops/components_order.rb index 84dba9a945..434e52579b 100644 --- a/Library/Homebrew/rubocops/components_order.rb +++ b/Library/Homebrew/rubocops/components_order.rb @@ -11,11 +11,6 @@ module RuboCop # - `component_precedence_list` has component hierarchy in a nested list # where each sub array contains components' details which are at same precedence level class ComponentsOrder < FormulaCop - # `aspell`: options and resources should be grouped by language - COMPONENT_ALLOWLIST = %w[ - aspell - ].freeze - def audit_formula(_node, _class_node, _parent_class_node, body_node) component_precedence_list = [ [{ name: :include, type: :method_call }], @@ -234,7 +229,7 @@ module RuboCop # Method to format message for reporting component precedence violations. def component_problem(c1, c2) - return if COMPONENT_ALLOWLIST.include?(@formula_name) + return if tap_style_exception? :components_order_exceptions problem "`#{format_component(c1)}` (line #{line_number(c1)}) " \ "should be put before `#{format_component(c2)}` " \ diff --git a/Library/Homebrew/test/rubocops/components_order_spec.rb b/Library/Homebrew/test/rubocops/components_order_spec.rb index 0a925d52ca..a6ae5c73c0 100644 --- a/Library/Homebrew/test/rubocops/components_order_spec.rb +++ b/Library/Homebrew/test/rubocops/components_order_spec.rb @@ -543,7 +543,5 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do end RUBY end - - include_examples "formulae exist", described_class::COMPONENT_ALLOWLIST end end From 7a8dd36003f66faec60cf6049a5ff0c33eb0158f Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 12:36:30 -0500 Subject: [PATCH 05/15] Migrate BINARY_BOOTSTRAP_FORMULA_URLS_ALLOWLIST --- Library/Homebrew/rubocops/urls.rb | 28 +-------------------- Library/Homebrew/test/rubocops/urls_spec.rb | 2 -- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/Library/Homebrew/rubocops/urls.rb b/Library/Homebrew/rubocops/urls.rb index 62e347666b..0e08a4897d 100644 --- a/Library/Homebrew/rubocops/urls.rb +++ b/Library/Homebrew/rubocops/urls.rb @@ -25,32 +25,6 @@ module RuboCop https://github.com/vifm/vifm/releases/download/v0.11/vifm-osx-0.11.tar.bz2 ].freeze - # These are formulae that, sadly, require an upstream binary to bootstrap. - BINARY_BOOTSTRAP_FORMULA_URLS_ALLOWLIST = %w[ - clozure-cl - crystal - fpc - ghc - ghc@8.6 - ghc@8.8 - go - go@1.9 - go@1.10 - go@1.11 - go@1.12 - go@1.13 - go@1.14 - haskell-stack - ldc - mlton - openjdk - openjdk@11 - openjdk@8 - pypy - sbcl - rust - ].freeze - 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) @@ -282,7 +256,7 @@ module RuboCop next if @formula_name.include?(match.to_s.downcase) next if url.match?(/.(patch|diff)(\?full_index=1)?$/) next if NOT_A_BINARY_URL_PREFIX_ALLOWLIST.any? { |prefix| url.start_with?(prefix) } - next if BINARY_BOOTSTRAP_FORMULA_URLS_ALLOWLIST.include?(@formula_name) + next if tap_style_exception? :binary_bootstrap_formula_urls_allowlist problem "#{url} looks like a binary package, not a source archive; " \ "homebrew/core is source-only." diff --git a/Library/Homebrew/test/rubocops/urls_spec.rb b/Library/Homebrew/test/rubocops/urls_spec.rb index 0be3154ee1..7e884bc71b 100644 --- a/Library/Homebrew/test/rubocops/urls_spec.rb +++ b/Library/Homebrew/test/rubocops/urls_spec.rb @@ -239,8 +239,6 @@ describe RuboCop::Cop::FormulaAudit::Urls do RUBY end end - - include_examples "formulae exist", described_class::BINARY_BOOTSTRAP_FORMULA_URLS_ALLOWLIST end describe RuboCop::Cop::FormulaAudit::PyPiUrls do From d59ce75d2a8399b9fe56dc0a85f04a4226e7e056 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 12:47:01 -0500 Subject: [PATCH 06/15] Migrate NOT_A_BINARY_URL_PREFIX_ALLOWLIST --- Library/Homebrew/rubocops/urls.rb | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/Library/Homebrew/rubocops/urls.rb b/Library/Homebrew/rubocops/urls.rb index 0e08a4897d..74bf2dd33a 100644 --- a/Library/Homebrew/rubocops/urls.rb +++ b/Library/Homebrew/rubocops/urls.rb @@ -10,21 +10,6 @@ module RuboCop # # @api private class Urls < FormulaCop - # These are parts of URLs that look like binaries but actually aren't. - NOT_A_BINARY_URL_PREFIX_ALLOWLIST = %w[ - https://downloads.sourceforge.net/project/astyle/astyle/ - https://downloads.sourceforge.net/project/bittwist/ - https://downloads.sourceforge.net/project/launch4j/ - https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard/archive/ - https://github.com/obihann/archey-osx - https://github.com/sindresorhus/macos-wallpaper/archive/ - https://raw.githubusercontent.com/liyanage/macosx-shell-scripts/ - https://osxbook.com/book/bonus/chapter8/core/download/gcore - https://naif.jpl.nasa.gov/pub/naif/toolkit/C/MacIntel_OSX_AppleC_64bit/packages/ - https://artifacts.videolan.org/x264/release-macos/ - https://github.com/vifm/vifm/releases/download/v0.11/vifm-osx-0.11.tar.bz2 - ].freeze - 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) @@ -255,7 +240,7 @@ module RuboCop audit_urls(urls, /(darwin|macos|osx)/i) do |match, url| next if @formula_name.include?(match.to_s.downcase) next if url.match?(/.(patch|diff)(\?full_index=1)?$/) - next if NOT_A_BINARY_URL_PREFIX_ALLOWLIST.any? { |prefix| url.start_with?(prefix) } + next if tap_style_exception? :not_a_binary_url_prefix_allowlist next if tap_style_exception? :binary_bootstrap_formula_urls_allowlist problem "#{url} looks like a binary package, not a source archive; " \ From a09613543a3afe494ff6bca2b6721c991a938bdb Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 12:49:49 -0500 Subject: [PATCH 07/15] Migrate REGEX_CASE_SENSITIVE_ALLOWLIST --- Library/Homebrew/rubocops/livecheck.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Library/Homebrew/rubocops/livecheck.rb b/Library/Homebrew/rubocops/livecheck.rb index f7e3bc55c4..b857858e47 100644 --- a/Library/Homebrew/rubocops/livecheck.rb +++ b/Library/Homebrew/rubocops/livecheck.rb @@ -218,10 +218,8 @@ module RuboCop # # @api private class LivecheckRegexCaseInsensitive < FormulaCop - REGEX_CASE_SENSITIVE_ALLOWLIST = %w[].freeze - def audit_formula(_node, _class_node, _parent_class_node, body_node) - return if REGEX_CASE_SENSITIVE_ALLOWLIST.include?(@formula_name) + return if tap_style_exception? :regex_case_sensitive_allowlist livecheck_node = find_block(body_node, :livecheck) return if livecheck_node.blank? From 44bfbd0112e690a5c94528085543b92fd720f706 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 13:13:09 -0500 Subject: [PATCH 08/15] Migrate uses_from_macos style lists --- Library/Homebrew/rubocops/extend/formula.rb | 7 +- Library/Homebrew/rubocops/uses_from_macos.rb | 89 +++---------------- .../test/rubocops/uses_from_macos_spec.rb | 2 - 3 files changed, 18 insertions(+), 80 deletions(-) diff --git a/Library/Homebrew/rubocops/extend/formula.rb b/Library/Homebrew/rubocops/extend/formula.rb index d3e75ea34f..e985631beb 100644 --- a/Library/Homebrew/rubocops/extend/formula.rb +++ b/Library/Homebrew/rubocops/extend/formula.rb @@ -473,8 +473,9 @@ module RuboCop match_obj[1] end - # Returns whether the current formula exists in the given style exception list - def tap_style_exception?(list) + # Returns whether the given formula exists in the given style exception list. + # Defaults to the current formula being checked. + def tap_style_exception?(list, formula = nil) if @tap_style_exceptions.blank? && formula_tap.present? @tap_style_exceptions = {} @@ -495,7 +496,7 @@ module RuboCop return false if @tap_style_exceptions.blank? return false unless @tap_style_exceptions.key? list - @tap_style_exceptions[list].include? @formula_name + @tap_style_exceptions[list].include?(formula || @formula_name) end private diff --git a/Library/Homebrew/rubocops/uses_from_macos.rb b/Library/Homebrew/rubocops/uses_from_macos.rb index 77804e677b..539de517fb 100644 --- a/Library/Homebrew/rubocops/uses_from_macos.rb +++ b/Library/Homebrew/rubocops/uses_from_macos.rb @@ -6,82 +6,20 @@ require "rubocops/extend/formula" module RuboCop module Cop module FormulaAudit + # This cop audits formulae that are keg-only because they are provided by macos. + class ProvidedByMacos < FormulaCop + def audit_formula(_node, _class_node, _parent_class_node, body_node) + find_method_with_args(body_node, :keg_only, :provided_by_macos) do + unless tap_style_exception? :provided_by_macos_formulae + problem "Formulae that are `keg_only :provided_by_macos` should be added to "\ + "`style_exceptions/provided_by_macos_formulae.json`" + end + end + end + end + # This cop audits `uses_from_macos` dependencies in formulae. class UsesFromMacos < FormulaCop - # Generate with: - # - # ``` - # brew ruby -e 'puts Formula.select {|f| f.keg_only_reason&.provided_by_macos? }.map(&:name).sort.join("\n")' - # ``` - # - # Not done at runtime as it's too slow and RuboCop doesn't have access. - PROVIDED_BY_MACOS_FORMULAE = %w[ - apr - bc - bison - bzip2 - cups - curl - dyld-headers - ed - expat - file-formula - flex - gcore - gnu-getopt - icu4c - krb5 - libarchive - libedit - libffi - libiconv - libpcap - libressl - libxml2 - libxslt - llvm - lsof - m4 - ncompress - ncurses - net-snmp - openldap - openlibm - pod2man - rpcgen - ruby - sqlite - ssh-copy-id - swift - tcl-tk - texinfo - unifdef - unzip - zip - zlib - ].freeze - - # These formulae aren't `keg_only :provided_by_macos` but are provided by - # macOS (or very similarly, e.g. OpenSSL where system provides LibreSSL). - # TODO: consider making some of these keg-only. - ALLOWED_USES_FROM_MACOS_DEPS = (PROVIDED_BY_MACOS_FORMULAE + %w[ - bash - cpio - expect - groff - gzip - openssl - openssl@1.1 - perl - php - python - python@3 - rsync - vim - xz - zsh - ]).freeze - def audit_formula(_node, _class_node, _parent_class_node, body_node) find_method_with_args(body_node, :uses_from_macos, /^"(.+)"/).each do |method| dep = if parameters(method).first.instance_of?(RuboCop::AST::StrNode) @@ -90,7 +28,8 @@ module RuboCop parameters(method).first.keys.first end - next if ALLOWED_USES_FROM_MACOS_DEPS.include?(string_content(dep)) + next if tap_style_exception? :provided_by_macos_formulae, string_content(dep) + next if tap_style_exception? :non_keg_only_provided_by_macos_formulae, string_content(dep) problem "`uses_from_macos` should only be used for macOS dependencies, not #{string_content(dep)}." end diff --git a/Library/Homebrew/test/rubocops/uses_from_macos_spec.rb b/Library/Homebrew/test/rubocops/uses_from_macos_spec.rb index 6a12800505..7495d680b2 100644 --- a/Library/Homebrew/test/rubocops/uses_from_macos_spec.rb +++ b/Library/Homebrew/test/rubocops/uses_from_macos_spec.rb @@ -17,6 +17,4 @@ describe RuboCop::Cop::FormulaAudit::UsesFromMacos do end RUBY end - - include_examples "formulae exist", described_class::ALLOWED_USES_FROM_MACOS_DEPS end From 2256e547d918bc9d5423761a38051b303712938b Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 27 Nov 2020 13:14:39 -0500 Subject: [PATCH 09/15] Remove unneeded "formulae exist" test --- .../helper/spec/shared_examples/formulae_exist.rb | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb diff --git a/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb b/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb deleted file mode 100644 index e52610016f..0000000000 --- a/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb +++ /dev/null @@ -1,13 +0,0 @@ -# typed: false -# frozen_string_literal: true - -shared_examples "formulae exist" do |array| - array.each do |f| - it "#{f} formula exists" do - core_tap = Pathname("#{HOMEBREW_LIBRARY_PATH}/../Taps/homebrew/homebrew-core") - formula_path = core_tap/"Formula/#{f}.rb" - alias_path = core_tap/"Aliases/#{f}" - expect(formula_path.exist? || alias_path.exist?).to be true - end - end -end From c181c9995e5232c44382bbf76eb795e57c8a1413 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Sun, 29 Nov 2020 14:21:06 -0500 Subject: [PATCH 10/15] style: add --reset-cache option --- Library/Homebrew/dev-cmd/style.rb | 8 +++++++- Library/Homebrew/style.rb | 6 +++++- docs/Manpage.md | 2 ++ manpages/brew.1 | 4 ++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/style.rb b/Library/Homebrew/dev-cmd/style.rb index efa36925a4..7e2fcbf136 100644 --- a/Library/Homebrew/dev-cmd/style.rb +++ b/Library/Homebrew/dev-cmd/style.rb @@ -27,6 +27,8 @@ module Homebrew description: "Fix style violations automatically using RuboCop's auto-correct feature." switch "--display-cop-names", description: "Include the RuboCop cop name for each violation in the output." + switch "--reset-cache", + description: "Reset the RuboCop cache." comma_array "--only-cops", description: "Specify a comma-separated list to check for violations of only the "\ "listed RuboCop cops." @@ -51,7 +53,11 @@ module Homebrew except_cops = args.except_cops options = { - fix: args.fix?, display_cop_names: args.display_cop_names?, debug: args.debug?, verbose: args.verbose? + fix: args.fix?, + display_cop_names: args.display_cop_names?, + reset_cache: args.reset_cache?, + debug: args.debug?, + verbose: args.verbose?, } if only_cops options[:only_cops] = only_cops diff --git a/Library/Homebrew/style.rb b/Library/Homebrew/style.rb index 3f10decf18..21689e5a56 100644 --- a/Library/Homebrew/style.rb +++ b/Library/Homebrew/style.rb @@ -40,6 +40,7 @@ module Homebrew fix: false, except_cops: nil, only_cops: nil, display_cop_names: false, + reset_cache: false, debug: false, verbose: false) raise ArgumentError, "Invalid output type: #{output_type.inspect}" unless [:print, :json].include?(output_type) @@ -54,6 +55,7 @@ module Homebrew fix: fix, except_cops: except_cops, only_cops: only_cops, display_cop_names: display_cop_names, + reset_cache: reset_cache, debug: debug, verbose: verbose) end @@ -71,7 +73,7 @@ module Homebrew end def run_rubocop(files, output_type, - fix: false, except_cops: nil, only_cops: nil, display_cop_names: false, + fix: false, except_cops: nil, only_cops: nil, display_cop_names: false, reset_cache: false, debug: false, verbose: false) Homebrew.install_bundler_gems! require "rubocop" @@ -130,6 +132,8 @@ module Homebrew cache_env = { "XDG_CACHE_HOME" => "#{HOMEBREW_CACHE}/style" } + FileUtils.rm_rf cache_env["XDG_CACHE_HOME"] if reset_cache + case output_type when :print args << "--debug" if debug diff --git a/docs/Manpage.md b/docs/Manpage.md index f8941af446..baf6700ac0 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1207,6 +1207,8 @@ including core code and all formulae. Fix style violations automatically using RuboCop's auto-correct feature. * `--display-cop-names`: Include the RuboCop cop name for each violation in the output. +* `--reset-cache`: + Reset the RuboCop cache. * `--only-cops`: Specify a comma-separated *`cops`* list to check for violations of only the listed RuboCop cops. * `--except-cops`: diff --git a/manpages/brew.1 b/manpages/brew.1 index 3bc17a0e5d..53a8875aaa 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1662,6 +1662,10 @@ Fix style violations automatically using RuboCop\'s auto\-correct feature\. Include the RuboCop cop name for each violation in the output\. . .TP +\fB\-\-reset\-cache\fR +Reset the RuboCop cache\. +. +.TP \fB\-\-only\-cops\fR Specify a comma\-separated \fIcops\fR list to check for violations of only the listed RuboCop cops\. . From 11a5e522ead82a39a6deb9433f7c2b06e8dc79da Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Sun, 29 Nov 2020 15:17:11 -0500 Subject: [PATCH 11/15] rubocop: don't rely on ActiveSupport --- Library/Homebrew/rubocops/extend/formula.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/rubocops/extend/formula.rb b/Library/Homebrew/rubocops/extend/formula.rb index e985631beb..1f47b3f031 100644 --- a/Library/Homebrew/rubocops/extend/formula.rb +++ b/Library/Homebrew/rubocops/extend/formula.rb @@ -476,7 +476,7 @@ module RuboCop # Returns whether the given formula exists in the given style exception list. # Defaults to the current formula being checked. def tap_style_exception?(list, formula = nil) - if @tap_style_exceptions.blank? && formula_tap.present? + if @tap_style_exceptions.nil? && !formula_tap.nil? @tap_style_exceptions = {} style_exceptions_dir = "#{File.dirname(File.dirname(@file_path))}/style_exceptions/*.json" @@ -487,13 +487,13 @@ module RuboCop rescue JSON::ParserError nil end - next if list_contents.blank? + next if list_contents.nil? || list_contents.count.zero? @tap_style_exceptions[list_name] = list_contents end end - return false if @tap_style_exceptions.blank? + return false if @tap_style_exceptions.nil? || @tap_style_exceptions.count.zero? return false unless @tap_style_exceptions.key? list @tap_style_exceptions[list].include?(formula || @formula_name) From ba63619f8efacd04ca6e75b593fec3fc95f56edb Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Mon, 30 Nov 2020 00:48:25 -0500 Subject: [PATCH 12/15] tests: remove final reference to formula_exist --- Library/Homebrew/test/spec_helper.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 182b57fa32..41465966eb 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -47,7 +47,6 @@ require "test/support/helper/output_as_tty" require "test/support/helper/spec/shared_context/homebrew_cask" if OS.mac? require "test/support/helper/spec/shared_context/integration_test" -require "test/support/helper/spec/shared_examples/formulae_exist" TEST_DIRECTORIES = [ CoreTap.instance.path/"Formula", From f8ff0f465f44943c470a2e683519d2b5459f109e Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Mon, 30 Nov 2020 12:29:07 -0500 Subject: [PATCH 13/15] tap: add tests for formula list methods --- Library/Homebrew/test/spec_helper.rb | 4 ++ Library/Homebrew/test/tap_spec.rb | 102 +++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 41465966eb..fc0c1ecbab 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -241,6 +241,10 @@ RSpec.configure do |config| CoreTap.instance.path/".git", CoreTap.instance.alias_dir, CoreTap.instance.path/"formula_renames.json", + CoreTap.instance.path/"tap_migrations.json", + CoreTap.instance.path/"audit_exceptions", + CoreTap.instance.path/"style_exceptions", + CoreTap.instance.path/"pypi_formula_mappings.json", *Pathname.glob("#{HOMEBREW_CELLAR}/*/"), ] diff --git a/Library/Homebrew/test/tap_spec.rb b/Library/Homebrew/test/tap_spec.rb index 78db926675..1beb1312a5 100644 --- a/Library/Homebrew/test/tap_spec.rb +++ b/Library/Homebrew/test/tap_spec.rb @@ -18,6 +18,8 @@ describe Tap do before do path.mkpath + (path/"audit_exceptions").mkpath + (path/"style_exceptions").mkpath end def setup_tap_files @@ -38,6 +40,27 @@ describe Tap do { "removed-formula": "homebrew/foo" } JSON + %w[audit_exceptions style_exceptions].each do |exceptions_directory| + (path/"#{exceptions_directory}/formula_list.json").write <<~JSON + [ "foo", "bar" ] + JSON + + (path/"#{exceptions_directory}/formula_hash.json").write <<~JSON + { "foo": "foo1", "bar": "bar1" } + JSON + end + + (path/"pypi_formula_mappings.json").write <<~JSON + { + "formula1": "foo", + "formula2": { + "package_name": "foo", + "extra_packages": ["bar"], + "exclude_packages": ["baz"] + } + } + JSON + [ cmd_file, manpage_file, @@ -320,6 +343,66 @@ describe Tap do expect(described_class.each).to be_an_instance_of(Enumerator) end end + + describe "Formula Lists" do + describe "#formula_renames" do + it "returns the formula_renames hash" do + setup_tap_files + + expected_result = { "oldname" => "foo" } + expect(subject.formula_renames).to eq expected_result + end + end + + describe "#tap_migrations" do + it "returns the tap_migrations hash" do + setup_tap_files + + expected_result = { "removed-formula" => "homebrew/foo" } + expect(subject.tap_migrations).to eq expected_result + end + end + + describe "#audit_exceptions" do + it "returns the audit_exceptions hash" do + setup_tap_files + + expected_result = { + formula_list: ["foo", "bar"], + formula_hash: { "foo" => "foo1", "bar" => "bar1" }, + } + expect(subject.audit_exceptions).to eq expected_result + end + end + + describe "#style_exceptions" do + it "returns the style_exceptions hash" do + setup_tap_files + + expected_result = { + formula_list: ["foo", "bar"], + formula_hash: { "foo" => "foo1", "bar" => "bar1" }, + } + expect(subject.style_exceptions).to eq expected_result + end + end + + describe "#pypi_formula_mappings" do + it "returns the pypi_formula_mappings hash" do + setup_tap_files + + expected_result = { + "formula1" => "foo", + "formula2" => { + "package_name" => "foo", + "extra_packages" => ["bar"], + "exclude_packages" => ["baz"], + }, + } + expect(subject.pypi_formula_mappings).to eq expected_result + end + end + end end describe CoreTap do @@ -341,6 +424,7 @@ describe CoreTap do end specify "files" do + path = CoreTap::TAP_DIRECTORY/"homebrew/homebrew-core" formula_file = subject.formula_dir/"foo.rb" formula_file.write <<~RUBY class Foo < Formula @@ -348,6 +432,18 @@ describe CoreTap do end RUBY + formula_list_file_json = '{ "foo": "foo1", "bar": "bar1" }' + formula_list_file_contents = { "foo" => "foo1", "bar" => "bar1" } + %w[ + formula_renames.json + tap_migrations.json + audit_exceptions/formula_list.json + style_exceptions/formula_hash.json + pypi_formula_mappings.json + ].each do |file| + (path/file).write formula_list_file_json + end + alias_file = subject.alias_dir/"bar" alias_file.parent.mkpath ln_s formula_file, alias_file @@ -358,5 +454,11 @@ describe CoreTap do expect(subject.aliases).to eq(["bar"]) expect(subject.alias_table).to eq("bar" => "foo") expect(subject.alias_reverse_table).to eq("foo" => ["bar"]) + + expect(subject.formula_renames).to eq formula_list_file_contents + expect(subject.tap_migrations).to eq formula_list_file_contents + expect(subject.audit_exceptions).to eq({ formula_list: formula_list_file_contents }) + expect(subject.style_exceptions).to eq({ formula_hash: formula_list_file_contents }) + expect(subject.pypi_formula_mappings).to eq formula_list_file_contents end end From 0c41d374c900fa7b495bf2e38e376286b6bb6dc9 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Mon, 30 Nov 2020 18:11:17 -0500 Subject: [PATCH 14/15] style: add tests for provided_by_macos and style_exceptions --- .../test/rubocops/provided_by_macos_spec.rb | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Library/Homebrew/test/rubocops/provided_by_macos_spec.rb diff --git a/Library/Homebrew/test/rubocops/provided_by_macos_spec.rb b/Library/Homebrew/test/rubocops/provided_by_macos_spec.rb new file mode 100644 index 0000000000..e2c331cc87 --- /dev/null +++ b/Library/Homebrew/test/rubocops/provided_by_macos_spec.rb @@ -0,0 +1,61 @@ +# typed: false +# frozen_string_literal: true + +require "rubocops/uses_from_macos" + +describe RuboCop::Cop::FormulaAudit::ProvidedByMacos do + subject(:cop) { described_class.new } + + let(:path) { Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" } + + before do + path.mkpath + (path/"style_exceptions").mkpath + end + + def setup_style_exceptions + (path/"style_exceptions/provided_by_macos_formulae.json").write <<~JSON + [ "foo", "bar" ] + JSON + end + + it "fails for formulae not in provided_by_macos_formulae list" do + setup_style_exceptions + + expect_offense(<<~RUBY, "#{path}/Formula/baz.rb") + class Baz < Formula + url "https://brew.sh/baz-1.0.tgz" + homepage "https://brew.sh" + + keg_only :provided_by_macos + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Formulae that are `keg_only :provided_by_macos` should be added to `style_exceptions/provided_by_macos_formulae.json` + end + RUBY + end + + it "succeeds for formulae in provided_by_macos_formulae list" do + setup_style_exceptions + + expect_no_offenses(<<~RUBY, "#{path}/Formula/foo.rb") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + homepage "https://brew.sh" + + keg_only :provided_by_macos + end + RUBY + end + + it "succeeds for formulae that are keg_only for a different reason" do + setup_style_exceptions + + expect_no_offenses(<<~RUBY, "#{path}/Formula/foo.rb") + class Baz < Formula + url "https://brew.sh/foo-1.0.tgz" + homepage "https://brew.sh" + + keg_only :versioned_formula + end + RUBY + end +end From 8d5dc762841c3362eee671a9688e08fdec693d37 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Mon, 30 Nov 2020 20:32:46 -0500 Subject: [PATCH 15/15] Satisfy brew typecheck --- Library/Homebrew/cli/args.rbi | 3 +++ Library/Homebrew/test/tap_spec.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/cli/args.rbi b/Library/Homebrew/cli/args.rbi index b9d3416f46..ccf30d30eb 100644 --- a/Library/Homebrew/cli/args.rbi +++ b/Library/Homebrew/cli/args.rbi @@ -129,6 +129,9 @@ module Homebrew sig { returns(T.nilable(T::Boolean)) } def markdown?; end + sig { returns(T.nilable(T::Boolean)) } + def reset_cache?; end + sig { returns(T.nilable(String)) } def tag; end diff --git a/Library/Homebrew/test/tap_spec.rb b/Library/Homebrew/test/tap_spec.rb index 1beb1312a5..3a5ddf8197 100644 --- a/Library/Homebrew/test/tap_spec.rb +++ b/Library/Homebrew/test/tap_spec.rb @@ -424,7 +424,7 @@ describe CoreTap do end specify "files" do - path = CoreTap::TAP_DIRECTORY/"homebrew/homebrew-core" + path = Tap::TAP_DIRECTORY/"homebrew/homebrew-core" formula_file = subject.formula_dir/"foo.rb" formula_file.write <<~RUBY class Foo < Formula