tap: cache more things at the Tap level

I added two new methods to cache both installed and all taps.
All taps includes core taps no matter if they're installed locally
since they're always provided by the API anyway.

This makes it easier to cache `Tap.each` while making the code
easier to reason about. It also will be useful because we'll
be able to avoid the `Tap.select(&:installed?` pattern that has
recently invaded the codebase.

Note: I also stopped clearing all tap instance caches before
tests. Running `Tap.each` would cache existing taps which would
lead to unexpected behavior since the only existing tap before
each test is the core tap. This is the only tap whose directory
is not cleaned up between tests so we just clear it's cache directly.
We also now clear all tap instances after tests as well regardless
of whether the API was used that time.
This commit is contained in:
apainintheneck 2024-03-05 23:53:52 -08:00
parent cd1f040949
commit 3834ef1b73
2 changed files with 33 additions and 18 deletions

View File

@ -402,6 +402,7 @@ class Tap
end end
clear_cache clear_cache
Tap.clear_cache
$stderr.ohai "Tapping #{name}" unless quiet $stderr.ohai "Tapping #{name}" unless quiet
args = %W[clone #{requested_remote} #{path}] args = %W[clone #{requested_remote} #{path}]
@ -546,6 +547,7 @@ class Tap
Commands.rebuild_commands_completion_list Commands.rebuild_commands_completion_list
clear_cache clear_cache
Tap.clear_cache
return if !manual || !official? return if !manual || !official?
@ -931,27 +933,42 @@ class Tap
other = Tap.fetch(other) if other.is_a?(String) other = Tap.fetch(other) if other.is_a?(String)
other.is_a?(self.class) && name == other.name other.is_a?(self.class) && name == other.name
end end
alias eql? ==
def self.each(&block) sig { returns(Integer) }
return to_enum unless block def hash
[self.class, name].hash
end
installed_taps = if TAP_DIRECTORY.directory? # All locally installed taps.
TAP_DIRECTORY.subdirs sig { returns(T::Array[Tap]) }
.flat_map(&:subdirs) def self.installed
.map(&method(:from_path)) cache[:installed] ||= if TAP_DIRECTORY.directory?
TAP_DIRECTORY.subdirs.flat_map(&:subdirs).map(&method(:from_path))
else else
[] []
end end
end
available_taps = if Homebrew::EnvConfig.no_install_from_api? # All locally installed and core taps. Core taps might not be installed locally when using the API.
installed_taps sig { returns(T::Array[Tap]) }
def self.all
cache[:all] ||= begin
core_taps = [
CoreTap.instance,
(CoreCaskTap.instance if OS.mac?), # rubocop:disable Homebrew/MoveToExtendOS
].compact
installed | core_taps
end
end
def self.each(&block)
if Homebrew::EnvConfig.no_install_from_api?
installed.each(&block)
else else
default_taps = T.let([CoreTap.instance], T::Array[Tap]) all.each(&block)
default_taps << CoreCaskTap.instance if OS.mac? # rubocop:disable Homebrew/MoveToExtendOS end
installed_taps + default_taps
end.sort_by(&:name).uniq
available_taps.each(&block)
end end
# An array of all installed {Tap} names. # An array of all installed {Tap} names.

View File

@ -204,7 +204,7 @@ RSpec.configure do |config|
config.around do |example| config.around do |example|
Homebrew.raise_deprecation_exceptions = true Homebrew.raise_deprecation_exceptions = true
Tap.each(&:clear_cache) Tap.installed.each(&:clear_cache)
Cachable::Registry.clear_all_caches Cachable::Registry.clear_all_caches
FormulaInstaller.clear_attempted FormulaInstaller.clear_attempted
FormulaInstaller.clear_installed FormulaInstaller.clear_installed
@ -244,9 +244,6 @@ RSpec.configure do |config|
rescue SystemExit => e rescue SystemExit => e
example.example.set_exception(e) example.example.set_exception(e)
ensure ensure
# This depends on `HOMEBREW_NO_INSTALL_FROM_API`.
Tap.each(&:clear_cache)
ENV.replace(@__env) ENV.replace(@__env)
Context.current = Context::ContextStruct.new Context.current = Context::ContextStruct.new
@ -257,6 +254,7 @@ RSpec.configure do |config|
@__stderr.close @__stderr.close
@__stdin.close @__stdin.close
Tap.all.each(&:clear_cache)
Cachable::Registry.clear_all_caches Cachable::Registry.clear_all_caches
FileUtils.rm_rf [ FileUtils.rm_rf [