diff --git a/Library/Homebrew/cask/cask_loader.rb b/Library/Homebrew/cask/cask_loader.rb index d9e8fd452a..66d4e572ae 100644 --- a/Library/Homebrew/cask/cask_loader.rb +++ b/Library/Homebrew/cask/cask_loader.rb @@ -215,8 +215,7 @@ module Cask sig { params(tapped_token: String).void } def initialize(tapped_token) - user, repo, token = tapped_token.split("/", 3) - tap = Tap.fetch(user, repo) + tap, token = Tap.with_cask_token(tapped_token) cask = CaskLoader.find_cask_in_tap(token, tap) super cask end @@ -543,9 +542,7 @@ module Cask new_token = tap.core_cask_tap? ? token : "#{tap}/#{token}" type = :rename elsif (new_tap_name = tap.tap_migrations[token].presence) - new_tap_user, new_tap_repo, new_token = new_tap_name.split("/", 3) - new_token ||= token - new_tap = Tap.fetch(new_tap_user, new_tap_repo) + new_tap, new_token = Tap.with_cask_token(new_tap_name) || [Tap.fetch(new_tap_name), token] new_tap.ensure_installed! new_tapped_token = "#{new_tap}/#{new_token}" diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 9a43cef169..a0d45bd333 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -1151,9 +1151,7 @@ module Formulary new_name = tap.core_tap? ? name : "#{tap}/#{name}" type = :rename elsif (new_tap_name = tap.tap_migrations[name].presence) - new_tap_user, new_tap_repo, new_name = new_tap_name.split("/", 3) - new_name ||= name - new_tap = Tap.fetch(new_tap_user, new_tap_repo) + new_tap, new_name = Tap.with_formula_name(new_tap_name) || [Tap.fetch(new_tap_name), name] new_tap.ensure_installed! new_tapped_name = "#{new_tap}/#{new_name}" diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index c22a1325a4..c634843165 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -39,19 +39,19 @@ class Tap #{HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR}/*.json ].freeze - def self.fetch(*args) - case args.length - when 1 - user, repo = args.first.split("/", 2) - when 2 - user = args.first - repo = args.second + sig { params(user: String, repo: String).returns(Tap) } + def self.fetch(user, repo = T.unsafe(nil)) + user, repo = user.split("/", 2) if repo.nil? + + if [user, repo].any? { |part| part.nil? || part.include?("/") } + raise ArgumentError, "Invalid tap name: '#{[*user, *repo].join("/")}'" end - raise "Invalid tap name '#{args.join("/")}'" if [user, repo].any? { |part| part.nil? || part.include?("/") } + user = T.must(user) + repo = T.must(repo) # We special case homebrew and linuxbrew so that users don't have to shift in a terminal. - user = user.capitalize if ["homebrew", "linuxbrew"].include? user + user = user.capitalize if ["homebrew", "linuxbrew"].include?(user) repo = repo.sub(HOMEBREW_OFFICIAL_REPO_PREFIXES_REGEX, "") return CoreTap.instance if ["Homebrew", "Linuxbrew"].include?(user) && ["core", "homebrew"].include?(repo) @@ -63,13 +63,16 @@ class Tap 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? - fetch(match[:user], match[:repo]) + return unless match + return unless (user = match[:user]) + return unless (repo = match[:repo]) + + fetch(user, repo) end # @private - sig { params(name: String).returns(T.nilable([T.attached_class, String])) } + sig { params(name: String).returns(T.nilable([Tap, String])) } def self.with_formula_name(name) return unless (match = name.match(HOMEBREW_TAP_FORMULA_REGEX)) @@ -85,7 +88,7 @@ class Tap end # @private - sig { params(token: String).returns(T.nilable([T.attached_class, String])) } + sig { params(token: String).returns(T.nilable([Tap, String])) } def self.with_cask_token(token) return unless (match = token.match(HOMEBREW_TAP_CASK_REGEX)) @@ -823,7 +826,7 @@ class Tap new_tap_user, new_tap_repo, new_name = new_name.split("/", 3) next unless new_name - new_tap = Tap.fetch(new_tap_user, new_tap_repo) + new_tap = Tap.fetch(T.must(new_tap_user), T.must(new_tap_repo)) hash["#{new_tap}/#{new_name}"] ||= [] hash["#{new_tap}/#{new_name}"] << old_name @@ -878,7 +881,7 @@ class Tap sig { params(other: T.nilable(T.any(String, Tap))).returns(T::Boolean) } def ==(other) other = Tap.fetch(other) if other.is_a?(String) - self.class == other.class && name == other.name + other.is_a?(self.class) && name == other.name end def self.each(&block) diff --git a/Library/Homebrew/test/cli/named_args_spec.rb b/Library/Homebrew/test/cli/named_args_spec.rb index b1f5c115cc..7022141099 100644 --- a/Library/Homebrew/test/cli/named_args_spec.rb +++ b/Library/Homebrew/test/cli/named_args_spec.rb @@ -312,7 +312,7 @@ RSpec.describe Homebrew::CLI::NamedArgs do it "raises an error for invalid tap" do taps = described_class.new("homebrew/foo", "barbaz") - expect { taps.to_taps }.to raise_error(RuntimeError, /Invalid tap name/) + expect { taps.to_taps }.to raise_error(ArgumentError, /Invalid tap name/) end end @@ -333,7 +333,7 @@ RSpec.describe Homebrew::CLI::NamedArgs do it "raises an error for invalid tap" do taps = described_class.new("homebrew/foo", "barbaz") - expect { taps.to_installed_taps }.to raise_error(RuntimeError, /Invalid tap name/) + expect { taps.to_installed_taps }.to raise_error(ArgumentError, /Invalid tap name/) end end end diff --git a/Library/Homebrew/test/tap_spec.rb b/Library/Homebrew/test/tap_spec.rb index cc7b7f5eda..b242cabe45 100644 --- a/Library/Homebrew/test/tap_spec.rb +++ b/Library/Homebrew/test/tap_spec.rb @@ -103,15 +103,15 @@ RSpec.describe Tap do expect do described_class.fetch("foo") - end.to raise_error(/Invalid tap name/) + end.to raise_error(ArgumentError, /Invalid tap name/) expect do described_class.fetch("homebrew/homebrew/bar") - end.to raise_error(/Invalid tap name/) + end.to raise_error(ArgumentError, /Invalid tap name/) expect do described_class.fetch("homebrew", "homebrew/baz") - end.to raise_error(/Invalid tap name/) + end.to raise_error(ArgumentError, /Invalid tap name/) end describe "::from_path" do