diff --git a/Library/Homebrew/api/cask.rb b/Library/Homebrew/api/cask.rb index 17ca86b716..8d0274cda8 100644 --- a/Library/Homebrew/api/cask.rb +++ b/Library/Homebrew/api/cask.rb @@ -10,9 +10,9 @@ module Homebrew # # @api private module Cask - class << self - include Cachable + extend Cachable + class << self private :cache sig { params(token: String).returns(Hash) } diff --git a/Library/Homebrew/api/formula.rb b/Library/Homebrew/api/formula.rb index 8704ec6ad4..ba5a1de330 100644 --- a/Library/Homebrew/api/formula.rb +++ b/Library/Homebrew/api/formula.rb @@ -10,9 +10,9 @@ module Homebrew # # @api private module Formula - class << self - include Cachable + extend Cachable + class << self private :cache sig { params(name: String).returns(Hash) } diff --git a/Library/Homebrew/extend/cachable.rb b/Library/Homebrew/extend/cachable.rb index b124c638e6..9c65e1bc36 100644 --- a/Library/Homebrew/extend/cachable.rb +++ b/Library/Homebrew/extend/cachable.rb @@ -1,4 +1,4 @@ -# typed: strict +# typed: true # frozen_string_literal: true module Cachable @@ -11,4 +11,43 @@ module Cachable def clear_cache cache.clear end + + # Collect all classes that mix in Cachable so that those caches can be cleared in-between tests. + if ENV["HOMEBREW_TESTS"] + def self.included(klass) + raise ArgumentError, "Don't use Cachable with singleton classes" if klass.singleton_class? + + super if defined?(super) + end + + # Ignore classes that get inherited from a lot and that have + # caches that we don't need to clear on the class level. + IGNORE_INHERITED_CLASSES = %w[Formula Cask].freeze + private_constant :IGNORE_INHERITED_CLASSES + + def self.extended(klass) + Registry.list << klass + klass.extend(Inherited) unless IGNORE_INHERITED_CLASSES.include?(klass.name) + super if defined?(super) + end + + module Inherited + def inherited(klass) + # A class might inherit Cachable at the instance level + # and in that case we just want to skip registering it. + Registry.list << klass if klass.respond_to?(:clear_cache) + super if defined?(super) + end + end + + module Registry + def self.list + @list ||= [] + end + + def self.clear_all_caches + list.each(&:clear_cache) + end + end + end end diff --git a/Library/Homebrew/readall.rb b/Library/Homebrew/readall.rb index 91407529aa..778b10ca65 100644 --- a/Library/Homebrew/readall.rb +++ b/Library/Homebrew/readall.rb @@ -9,8 +9,9 @@ require "system_command" # # @api private module Readall + extend Cachable + class << self - include Cachable include SystemCommand::Mixin # TODO: remove this once the `MacOS` module is undefined on Linux diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 9d2f2d10ee..f9ed707426 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -202,16 +202,7 @@ RSpec.configure do |config| config.around do |example| Homebrew.raise_deprecation_exceptions = true - Formulary.clear_cache - Tap.each(&:clear_cache) - Tap.clear_cache - DependencyCollector.clear_cache - Formula.clear_cache - Keg.clear_cache - Tab.clear_cache - Dependency.clear_cache - Requirement.clear_cache - Readall.clear_cache if defined?(Readall) + Cachable::Registry.clear_all_caches FormulaInstaller.clear_attempted FormulaInstaller.clear_installed FormulaInstaller.clear_fetched @@ -263,15 +254,7 @@ RSpec.configure do |config| @__stderr.close @__stdin.close - Formulary.clear_cache - Tap.clear_cache - DependencyCollector.clear_cache - Formula.clear_cache - Keg.clear_cache - Tab.clear_cache - Dependency.clear_cache - Requirement.clear_cache - Readall.clear_cache if defined?(Readall) + Cachable::Registry.clear_all_caches FileUtils.rm_rf [ *TEST_DIRECTORIES,