From 03278ab369ef466f06414b9a2597da7c2faa566a Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 23 Feb 2024 15:11:54 +0100 Subject: [PATCH] Add type signatures for `Tap`. --- Library/Homebrew/diagnostic.rb | 2 +- Library/Homebrew/tap.rb | 73 ++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 23f1b53e22d6e0..9ebc3e3be87f03 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -537,7 +537,7 @@ def check_casktap_integrity core_cask_tap = CoreCaskTap.instance return unless core_cask_tap.installed? - broken_tap(core_cask_tap) || examine_git_origin(core_cask_tap.git_repo, core_cask_tap.remote) + broken_tap(core_cask_tap) || examine_git_origin(core_cask_tap.git_repo, T.must(core_cask_tap.remote)) end sig { returns(T.nilable(String)) } diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 887ca69770a1c0..50bd6da4501124 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -55,6 +55,7 @@ def self.fetch(user, repo = T.unsafe(nil)) cache.fetch(cache_key) { |key| cache[key] = Tap.new(user, repo) } end + # sig { params(path: T.any(String, Pathname)).returns(T.nilable(T.attached_class)) } def self.from_path(path) match = File.expand_path(path).match(HOMEBREW_TAP_PATH_REGEX) return if match.blank? || match[:user].blank? || match[:repo].blank? @@ -105,6 +106,7 @@ def self.install_default_cask_tap_if_necessary(force: false) attr_reader :git_repo # @private + sig { params(user: String, repo: String).void } def initialize(user, repo) @user = user @repo = repo @@ -115,6 +117,7 @@ def initialize(user, repo) end # Clear internal cache. + sig { void } def clear_cache @remote = nil @repo_var = nil @@ -163,6 +166,7 @@ def ensure_installed! # The remote path to this {Tap}. # e.g. `https://github.com/user/homebrew-repo` + sig { returns(T.nilable(String)) } def remote return default_remote unless installed? @@ -171,6 +175,7 @@ def remote # The remote repository name of this {Tap}. # e.g. `user/homebrew-repo` + sig { returns(T.nilable(String)) } def remote_repo @remote_repo ||= remote&.delete_prefix("https://github.com/") &.delete_prefix("git@github.com:") @@ -184,16 +189,19 @@ def default_remote end # @private + sig { returns(String) } def repo_var @repo_var ||= path.relative_path_from(TAP_DIRECTORY).to_s.tr("^A-Za-z0-9", "_").upcase end # True if this {Tap} is a Git repository. + sig { returns(T::Boolean) } def git? git_repo.git_repo? end # Git branch for this {Tap}. + sig { returns(T.nilable(String)) } def git_branch raise TapUnavailableError, name unless installed? @@ -201,6 +209,7 @@ def git_branch end # Git HEAD for this {Tap}. + sig { returns(T.nilable(String)) } def git_head raise TapUnavailableError, name unless installed? @@ -208,6 +217,7 @@ def git_head end # Time since last git commit for this {Tap}. + sig { returns(T.nilable(String)) } def git_last_commit raise TapUnavailableError, name unless installed? @@ -223,16 +233,19 @@ def issues_url "#{default_remote}/issues" end + sig { returns(String) } def to_s name end # True if this {Tap} is an official Homebrew tap. + sig { returns(T::Boolean) } def official? user == "Homebrew" end # True if the remote of this {Tap} is a private repository. + sig { returns(T::Boolean) } def private? return @private if instance_variable_defined?(:@private) @@ -248,11 +261,13 @@ def config end # True if this {Tap} has been installed. + sig { returns(T::Boolean) } def installed? path.directory? end # True if this {Tap} is not a full clone. + sig { returns(T::Boolean) } def shallow? (path/".git/shallow").exist? end @@ -278,6 +293,16 @@ def core_cask_tap? # @param custom_remote [Boolean] If set, change the tap's remote if already installed. # @param verify [Boolean] If set, verify all the formula, casks and aliases in the tap are valid. # @param force [Boolean] If set, force core and cask taps to install even under API mode. + sig { + params( + quiet: T::Boolean, + clone_target: T.nilable(T.any(String, Pathname)), + force_auto_update: T.nilable(T::Boolean), + custom_remote: T::Boolean, + verify: T::Boolean, + force: T::Boolean, + ).void + } def install(quiet: false, clone_target: nil, force_auto_update: nil, custom_remote: false, verify: false, force: false) require "descriptions" @@ -295,7 +320,7 @@ def install(quiet: false, clone_target: nil, force_auto_update: nil, requested_remote = clone_target || default_remote if installed? && !custom_remote - raise TapRemoteMismatchError.new(name, @remote, requested_remote) if clone_target && requested_remote != remote + raise TapRemoteMismatchError.new(name, remote, requested_remote) if clone_target && requested_remote != remote raise TapAlreadyTappedError, name if force_auto_update.nil? && !shallow? end @@ -403,6 +428,7 @@ def install(quiet: false, clone_target: nil, force_auto_update: nil, EOS end + sig { void } def link_completions_and_manpages command = "brew tap --repair" Utils::Link.link_manpages(path, command) @@ -415,6 +441,7 @@ def link_completions_and_manpages end end + sig { params(requested_remote: T.nilable(String), quiet: T::Boolean).void } def fix_remote_configuration(requested_remote: nil, quiet: false) if requested_remote.present? path.cd do @@ -448,6 +475,7 @@ def fix_remote_configuration(requested_remote: nil, quiet: false) end # Uninstall this {Tap}. + sig { params(manual: T::Boolean).void } def uninstall(manual: false) require "descriptions" raise TapUnavailableError, name unless installed? @@ -484,6 +512,7 @@ def uninstall(manual: false) end # True if the {#remote} of {Tap} is customized. + sig { returns(T::Boolean) } def custom_remote? !remote&.casecmp(default_remote)&.zero? end @@ -526,6 +555,8 @@ def relative_cask_path(token) .delete_prefix("#{path}/") end + # @private + sig { returns(T::Array[String]) } def contents contents = [] @@ -830,6 +861,11 @@ def ==(other) self.class == other.class && name == other.name end + sig { + override.params( + block: T.nilable(T.proc.params(arg0: T.attached_class).returns(T.untyped)), + ).returns(T::Enumerable[T.attached_class]) + } def self.each(&block) return to_enum unless block @@ -882,6 +918,7 @@ def alias_file_to_name(file) "#{name}/#{file.basename}" end + sig { params(list: Symbol, formula_or_cask: String, value: T.untyped).returns(T.untyped) } def audit_exception(list, formula_or_cask, value = nil) return false if audit_exceptions.blank? return false unless audit_exceptions.key? list @@ -893,7 +930,7 @@ def audit_exception(list, formula_or_cask, value = nil) list.include? formula_or_cask when Hash return false unless list.include? formula_or_cask - return list[formula_or_cask] if value.blank? + return list[formula_or_cask] if value.nil? list[formula_or_cask] == value end @@ -901,6 +938,7 @@ def audit_exception(list, formula_or_cask, value = nil) private + sig { returns(T::Boolean) } def read_or_set_private_config case config["private"] when "true" then true @@ -986,7 +1024,7 @@ class CoreTap < AbstractCoreTap # @private sig { void } def initialize - super "Homebrew", "core" + super("Homebrew", "core") end sig { override.void } @@ -996,7 +1034,7 @@ def ensure_installed! super end - sig { returns(String) } + sig { override.returns(T.nilable(String)) } def remote return super if Homebrew::EnvConfig.no_install_from_api? @@ -1004,6 +1042,16 @@ def remote end # CoreTap never allows shallow clones (on request from GitHub). + sig { + override.params( + quiet: T::Boolean, + clone_target: T.nilable(T.any(String, Pathname)), + force_auto_update: T.nilable(T::Boolean), + custom_remote: T::Boolean, + verify: T::Boolean, + force: T::Boolean, + ).void + } def install(quiet: false, clone_target: nil, force_auto_update: nil, custom_remote: false, verify: false, force: false) remote = Homebrew::EnvConfig.core_git_remote # set by HOMEBREW_CORE_GIT_REMOTE @@ -1021,7 +1069,7 @@ def install(quiet: false, clone_target: nil, force_auto_update: nil, end # @private - sig { params(manual: T::Boolean).void } + sig { override.params(manual: T::Boolean).void } def uninstall(manual: false) raise "Tap#uninstall is not available for CoreTap" if Homebrew::EnvConfig.no_install_from_api? @@ -1029,7 +1077,7 @@ def uninstall(manual: false) end # @private - sig { returns(T::Boolean) } + sig { override.returns(T::Boolean) } def core_tap? true end @@ -1041,7 +1089,7 @@ def linuxbrew_core? end # @private - sig { returns(Pathname) } + sig { override.returns(Pathname) } def formula_dir @formula_dir ||= begin ensure_installed! @@ -1083,7 +1131,7 @@ def formula_renames end # @private - sig { returns(Hash) } + sig { override.returns(T::Hash[String, String]) } def tap_migrations @tap_migrations ||= if Homebrew::EnvConfig.no_install_from_api? ensure_installed! @@ -1091,7 +1139,7 @@ def tap_migrations else migrations, = Homebrew::API.fetch_json_api_file "formula_tap_migrations.jws.json", stale_seconds: TAP_MIGRATIONS_STALE_SECONDS - migrations + T.cast(migrations, T::Hash[String, String]) end end @@ -1182,7 +1230,7 @@ class CoreCaskTap < AbstractCoreTap # @private sig { void } def initialize - super "Homebrew", "cask" + super("Homebrew", "cask") end # @private @@ -1234,14 +1282,15 @@ def cask_renames end end - sig { override.returns(Hash) } + # @private + sig { override.returns(T::Hash[String, String]) } def tap_migrations @tap_migrations ||= if Homebrew::EnvConfig.no_install_from_api? super else migrations, = Homebrew::API.fetch_json_api_file "cask_tap_migrations.jws.json", stale_seconds: TAP_MIGRATIONS_STALE_SECONDS - migrations + T.cast(migrations, T::Hash[String, String]) end end end