Set correct tap when loading installed casks
This commit is contained in:
parent
c0f08f82b9
commit
8cb62b1398
@ -503,13 +503,26 @@ module Cask
|
|||||||
.returns(T.nilable(T.attached_class))
|
.returns(T.nilable(T.attached_class))
|
||||||
}
|
}
|
||||||
def self.try_new(ref, warn: false)
|
def self.try_new(ref, warn: false)
|
||||||
return unless ref.is_a?(String)
|
token = if ref.is_a?(String)
|
||||||
|
ref
|
||||||
|
elsif ref.is_a?(Pathname)
|
||||||
|
ref.basename(ref.extname).to_s
|
||||||
|
end
|
||||||
|
return unless token
|
||||||
|
|
||||||
possible_installed_cask = Cask.new(ref)
|
possible_installed_cask = Cask.new(token)
|
||||||
return unless (installed_caskfile = possible_installed_cask.installed_caskfile)
|
return unless (installed_caskfile = possible_installed_cask.installed_caskfile)
|
||||||
|
|
||||||
new(installed_caskfile)
|
new(installed_caskfile)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { params(path: T.any(Pathname, String), token: String).void }
|
||||||
|
def initialize(path, token: T.unsafe(nil))
|
||||||
|
super
|
||||||
|
|
||||||
|
installed_tap = Cask.new(@token).tab.tap
|
||||||
|
@tap = installed_tap if installed_tap
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Pseudo-loader which raises an error when trying to load the corresponding cask.
|
# Pseudo-loader which raises an error when trying to load the corresponding cask.
|
||||||
@ -598,6 +611,32 @@ module Cask
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { params(ref: String, config: T.nilable(Config), warn: T::Boolean).returns(Cask) }
|
||||||
|
def self.load_installed_cask(ref, config: nil, warn: true)
|
||||||
|
tap, token = Tap.with_cask_token(ref)
|
||||||
|
token ||= ref
|
||||||
|
tap ||= Cask.new(ref).tab.tap
|
||||||
|
|
||||||
|
if tap.nil?
|
||||||
|
self.load(token, config:, warn:)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
self.load("#{tap}/#{token}", config:, warn:)
|
||||||
|
rescue CaskUnavailableError
|
||||||
|
# cask may be migrated to different tap. Try to search in all taps.
|
||||||
|
self.load(token, config:, warn:)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(path: Pathname, config: T.nilable(Config), warn: T::Boolean).returns(Cask) }
|
||||||
|
def self.load_from_installed_caskfile(path, config: nil, warn: true)
|
||||||
|
loader = FromInstalledPathLoader.try_new(path, warn:)
|
||||||
|
loader ||= NullLoader.new(path)
|
||||||
|
|
||||||
|
loader.load(config:)
|
||||||
|
end
|
||||||
|
|
||||||
def self.default_path(token)
|
def self.default_path(token)
|
||||||
find_cask_in_tap(token.to_s.downcase, CoreCaskTap.instance)
|
find_cask_in_tap(token.to_s.downcase, CoreCaskTap.instance)
|
||||||
end
|
end
|
||||||
|
@ -56,7 +56,7 @@ module Cask
|
|||||||
sig { params(config: T.nilable(Config)).returns(T::Array[Cask]) }
|
sig { params(config: T.nilable(Config)).returns(T::Array[Cask]) }
|
||||||
def self.casks(config: nil)
|
def self.casks(config: nil)
|
||||||
tokens.sort.filter_map do |token|
|
tokens.sort.filter_map do |token|
|
||||||
CaskLoader.load(token, config:, warn: false)
|
CaskLoader.load_installed_cask(token, config:, warn: false)
|
||||||
rescue TapCaskAmbiguityError => e
|
rescue TapCaskAmbiguityError => e
|
||||||
T.must(e.loaders.first).load(config:)
|
T.must(e.loaders.first).load(config:)
|
||||||
rescue
|
rescue
|
||||||
|
@ -189,7 +189,18 @@ module Homebrew
|
|||||||
if want_keg_like_cask &&
|
if want_keg_like_cask &&
|
||||||
(installed_caskfile = candidate_cask.installed_caskfile) &&
|
(installed_caskfile = candidate_cask.installed_caskfile) &&
|
||||||
installed_caskfile.exist?
|
installed_caskfile.exist?
|
||||||
Cask::CaskLoader.load(installed_caskfile)
|
cask = Cask::CaskLoader.load_from_installed_caskfile(installed_caskfile)
|
||||||
|
|
||||||
|
requested_tap, requested_token = Tap.with_cask_token(name)
|
||||||
|
if requested_tap && requested_token
|
||||||
|
installed_cask_tap = cask.tab.tap
|
||||||
|
|
||||||
|
if installed_cask_tap && installed_cask_tap != requested_tap
|
||||||
|
raise Cask::TapCaskUnavailableError.new(requested_tap, requested_token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cask
|
||||||
else
|
else
|
||||||
candidate_cask
|
candidate_cask
|
||||||
end
|
end
|
||||||
@ -405,6 +416,16 @@ module Homebrew
|
|||||||
rack = Formulary.to_rack(name.downcase)
|
rack = Formulary.to_rack(name.downcase)
|
||||||
|
|
||||||
kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
|
kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
|
||||||
|
|
||||||
|
requested_tap, requested_formula = Tap.with_formula_name(name)
|
||||||
|
if requested_tap && requested_formula
|
||||||
|
kegs = kegs.select do |keg|
|
||||||
|
keg.tab.tap == requested_tap
|
||||||
|
end
|
||||||
|
|
||||||
|
raise NoSuchKegFromTapError.new(requested_formula, requested_tap) if kegs.none?
|
||||||
|
end
|
||||||
|
|
||||||
raise NoSuchKegError, name if kegs.none?
|
raise NoSuchKegError, name if kegs.none?
|
||||||
|
|
||||||
[rack, kegs]
|
[rack, kegs]
|
||||||
|
@ -61,6 +61,18 @@ class NoSuchKegError < RuntimeError
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when a keg from a specific tap doesn't exist.
|
||||||
|
class NoSuchKegFromTapError < RuntimeError
|
||||||
|
attr_reader :name, :tap
|
||||||
|
|
||||||
|
sig { params(name: String, tap: Tap).void }
|
||||||
|
def initialize(name, tap)
|
||||||
|
@name = name
|
||||||
|
@tap = tap
|
||||||
|
super "No such keg: #{HOMEBREW_CELLAR}/#{name} from tap #{tap}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Raised when an invalid attribute is used in a formula.
|
# Raised when an invalid attribute is used in a formula.
|
||||||
class FormulaValidationError < StandardError
|
class FormulaValidationError < StandardError
|
||||||
attr_reader :attr, :formula
|
attr_reader :attr, :formula
|
||||||
|
@ -184,4 +184,60 @@ RSpec.describe Cask::CaskLoader, :cask do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "::load_installed_cask" do
|
||||||
|
let(:foo_tap) { Tap.fetch("user", "foo") }
|
||||||
|
let(:bar_tap) { Tap.fetch("user", "bar") }
|
||||||
|
|
||||||
|
let(:blank_tab) { instance_double(Cask::Tab, tap: nil) }
|
||||||
|
let(:installed_tab) { instance_double(Cask::Tab, tap: bar_tap) }
|
||||||
|
|
||||||
|
let(:cask_with_foo_tap) { instance_double(Cask::Cask, token: "test-cask", tap: foo_tap) }
|
||||||
|
let(:cask_with_bar_tap) { instance_double(Cask::Cask, token: "test-cask", tap: bar_tap) }
|
||||||
|
|
||||||
|
let(:load_args) { { config: nil, warn: true } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(described_class).to receive(:load).with("test-cask", load_args).and_return(cask_with_foo_tap)
|
||||||
|
allow(described_class).to receive(:load).with("user/foo/test-cask", load_args).and_return(cask_with_foo_tap)
|
||||||
|
allow(described_class).to receive(:load).with("user/bar/test-cask", load_args).and_return(cask_with_bar_tap)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct cask when no tap is specified and no tab exists" do
|
||||||
|
allow_any_instance_of(Cask::Cask).to receive(:tab).and_return(blank_tab)
|
||||||
|
expect(described_class).to receive(:load).with("test-cask", load_args)
|
||||||
|
|
||||||
|
expect(described_class.load_installed_cask("test-cask").tap).to eq(foo_tap)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct cask when no tap is specified but a tab exists" do
|
||||||
|
allow_any_instance_of(Cask::Cask).to receive(:tab).and_return(installed_tab)
|
||||||
|
expect(described_class).to receive(:load).with("user/bar/test-cask", load_args)
|
||||||
|
|
||||||
|
expect(described_class.load_installed_cask("test-cask").tap).to eq(bar_tap)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct cask when a tap is specified and no tab exists" do
|
||||||
|
allow_any_instance_of(Cask::Cask).to receive(:tab).and_return(blank_tab)
|
||||||
|
expect(described_class).to receive(:load).with("user/bar/test-cask", load_args)
|
||||||
|
|
||||||
|
expect(described_class.load_installed_cask("user/bar/test-cask").tap).to eq(bar_tap)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct cask when no tap is specified and a tab exists" do
|
||||||
|
allow_any_instance_of(Cask::Cask).to receive(:tab).and_return(installed_tab)
|
||||||
|
expect(described_class).to receive(:load).with("user/foo/test-cask", load_args)
|
||||||
|
|
||||||
|
expect(described_class.load_installed_cask("user/foo/test-cask").tap).to eq(foo_tap)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct cask when no tap is specified and the tab lists an tap that isn't installed" do
|
||||||
|
allow_any_instance_of(Cask::Cask).to receive(:tab).and_return(installed_tab)
|
||||||
|
expect(described_class).to receive(:load).with("user/bar/test-cask", load_args)
|
||||||
|
.and_raise(Cask::CaskUnavailableError.new("test-cask", bar_tap))
|
||||||
|
expect(described_class).to receive(:load).with("test-cask", load_args)
|
||||||
|
|
||||||
|
expect(described_class.load_installed_cask("test-cask").tap).to eq(foo_tap)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -217,6 +217,36 @@ RSpec.describe Homebrew::CLI::NamedArgs do
|
|||||||
it "when there are no matching kegs returns an empty array" do
|
it "when there are no matching kegs returns an empty array" do
|
||||||
expect(described_class.new.to_kegs).to be_empty
|
expect(described_class.new.to_kegs).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "raises an error when a Keg is unavailable" do
|
||||||
|
expect { described_class.new("baz").to_kegs }.to raise_error NoSuchKegError
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a keg specifies a tap" do
|
||||||
|
let(:tab) { instance_double(Tab, tap: Tap.fetch("user", "repo")) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow_any_instance_of(Keg).to receive(:tab).and_return(tab)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns kegs if no tap is specified" do
|
||||||
|
stub_formula_loader bar, "user/repo/bar"
|
||||||
|
|
||||||
|
expect(described_class.new("bar").to_kegs.map(&:name)).to eq ["bar"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns kegs if the tap is specified" do
|
||||||
|
stub_formula_loader bar, "user/repo/bar"
|
||||||
|
|
||||||
|
expect(described_class.new("user/repo/bar").to_kegs.map(&:name)).to eq ["bar"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an error if there is no tap match" do
|
||||||
|
stub_formula_loader bar, "other/tap/bar"
|
||||||
|
|
||||||
|
expect { described_class.new("other/tap/bar").to_kegs }.to raise_error(NoSuchKegFromTapError)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#to_default_kegs" do
|
describe "#to_default_kegs" do
|
||||||
|
@ -19,6 +19,14 @@ RSpec.describe "Exception" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe NoSuchKegFromTapError do
|
||||||
|
subject(:error) { described_class.new("foo", tap) }
|
||||||
|
|
||||||
|
let(:tap) { instance_double(Tap, to_s: "u/r") }
|
||||||
|
|
||||||
|
it(:to_s) { expect(error.to_s).to eq("No such keg: #{HOMEBREW_CELLAR}/foo from tap u/r") }
|
||||||
|
end
|
||||||
|
|
||||||
describe NoSuchKegError do
|
describe NoSuchKegError do
|
||||||
subject(:error) { described_class.new("foo") }
|
subject(:error) { described_class.new("foo") }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user