Make Cask#to_h work without the API

Set metadata when we load casks from the source API.

Set `@tap_git_head` manually.

Also, allow `auto_update` to receive false.
This is only done for consistency.

Stop double printing the `kext` caveat.

Handle Array elements correctly when substituting
path elements in artifacts. This affected how the
Uninstall Signal keys were evaluated (they are
represented as arrays of arrays).
This commit is contained in:
apainintheneck 2023-02-18 12:08:54 -08:00
parent 39dd7e987d
commit c19017c6bd
6 changed files with 32 additions and 22 deletions

View File

@ -45,6 +45,8 @@ module Cask
directives[:signal] = Array(directives[:signal]).flatten.each_slice(2).to_a directives[:signal] = Array(directives[:signal]).flatten.each_slice(2).to_a
@directives = directives @directives = directives
# This is already included when loading from the API.
return if cask.loaded_from_api?
return unless directives.key?(:kext) return unless directives.key?(:kext)
cask.caveats do cask.caveats do

View File

@ -17,6 +17,7 @@ module Cask
extend Forwardable extend Forwardable
extend Searchable extend Searchable
extend Predicable
include Metadata include Metadata
# Needs a leading slash to avoid `File.expand.path` complaining about non-absolute home. # Needs a leading slash to avoid `File.expand.path` complaining about non-absolute home.
@ -27,10 +28,11 @@ module Cask
# TODO: can be removed when API JSON is regenerated with HOMEBREW_PREFIX_PLACEHOLDER. # TODO: can be removed when API JSON is regenerated with HOMEBREW_PREFIX_PLACEHOLDER.
HOMEBREW_OLD_PREFIX_PLACEHOLDER = "$(brew --prefix)" HOMEBREW_OLD_PREFIX_PLACEHOLDER = "$(brew --prefix)"
attr_reader :token, :sourcefile_path, :source, :config, :default_config, :loaded_from_api, :loader attr_reader :token, :sourcefile_path, :source, :config, :default_config, :loader
attr_accessor :download, :allow_reassignment attr_accessor :download, :allow_reassignment
attr_predicate :loaded_from_api?
class << self class << self
def generating_hash! def generating_hash!
return if generating_hash? return if generating_hash?
@ -83,14 +85,14 @@ module Cask
@tap @tap
end end
def initialize(token, sourcefile_path: nil, source: nil, tap: nil, def initialize(token, sourcefile_path: nil, source: nil, tap: nil, loaded_from_api: false,
config: nil, allow_reassignment: false, loader: nil, &block) config: nil, allow_reassignment: false, loader: nil, &block)
@token = token @token = token
@sourcefile_path = sourcefile_path @sourcefile_path = sourcefile_path
@source = source @source = source
@tap = tap @tap = tap
@allow_reassignment = allow_reassignment @allow_reassignment = allow_reassignment
@loaded_from_api = false @loaded_from_api = loaded_from_api
@loader = loader @loader = loader
@block = block @block = block
@ -278,7 +280,8 @@ module Cask
end end
def populate_from_api!(json_cask) def populate_from_api!(json_cask)
@loaded_from_api = true raise ArgumentError, "Expected cask to be loaded from the API" unless loaded_from_api?
@languages = json_cask[:languages] @languages = json_cask[:languages]
@tap_git_head = json_cask[:tap_git_head] @tap_git_head = json_cask[:tap_git_head]
@ruby_source_checksum = json_cask[:ruby_source_checksum].freeze @ruby_source_checksum = json_cask[:ruby_source_checksum].freeze
@ -334,7 +337,7 @@ module Cask
end end
def to_hash_with_variations def to_hash_with_variations
if loaded_from_api && !Homebrew::EnvConfig.no_install_from_api? if loaded_from_api? && !Homebrew::EnvConfig.no_install_from_api?
return api_to_local_hash(Homebrew::API::Cask.all_casks[token]) return api_to_local_hash(Homebrew::API::Cask.all_casks[token])
end end

View File

@ -219,11 +219,17 @@ module Cask
def load(config:) def load(config:)
json_cask = @from_json || Homebrew::API::Cask.all_casks[token] json_cask = @from_json || Homebrew::API::Cask.all_casks[token]
cask_source = JSON.pretty_generate(json_cask)
cask_options = {
loaded_from_api: true,
source: JSON.pretty_generate(json_cask),
config: config,
loader: self,
}
json_cask = Homebrew::API.merge_variations(json_cask).deep_symbolize_keys.freeze json_cask = Homebrew::API.merge_variations(json_cask).deep_symbolize_keys.freeze
tap = Tap.fetch(json_cask[:tap]) if json_cask[:tap].to_s.include?("/") cask_options[:tap] = Tap.fetch(json_cask[:tap]) if json_cask[:tap].to_s.include?("/")
user_agent = json_cask.dig(:url_specs, :user_agent) user_agent = json_cask.dig(:url_specs, :user_agent)
json_cask[:url_specs][:user_agent] = user_agent[1..].to_sym if user_agent && user_agent[0] == ":" json_cask[:url_specs][:user_agent] = user_agent[1..].to_sym if user_agent && user_agent[0] == ":"
@ -231,7 +237,7 @@ module Cask
json_cask[:url_specs][:using] = using.to_sym json_cask[:url_specs][:using] = using.to_sym
end end
api_cask = Cask.new(token, tap: tap, source: cask_source, config: config, loader: self) do api_cask = Cask.new(token, **cask_options) do
version json_cask[:version] version json_cask[:version]
if json_cask[:sha256] == "no_check" if json_cask[:sha256] == "no_check"
@ -248,7 +254,7 @@ module Cask
desc json_cask[:desc] desc json_cask[:desc]
homepage json_cask[:homepage] homepage json_cask[:homepage]
auto_updates json_cask[:auto_updates] if json_cask[:auto_updates].present? auto_updates json_cask[:auto_updates] unless json_cask[:auto_updates].nil?
conflicts_with(**json_cask[:conflicts_with]) if json_cask[:conflicts_with].present? conflicts_with(**json_cask[:conflicts_with]) if json_cask[:conflicts_with].present?
if json_cask[:depends_on].present? if json_cask[:depends_on].present?
@ -289,7 +295,7 @@ module Cask
json_cask[:artifacts].each do |artifact| json_cask[:artifacts].each do |artifact|
# convert generic string replacements into actual ones # convert generic string replacements into actual ones
artifact = cask.loader.from_h_hash_gsubs(artifact, appdir) artifact = cask.loader.from_h_gsubs(artifact, appdir)
key = artifact.keys.first key = artifact.keys.first
if artifact[key].nil? if artifact[key].nil?
# for artifacts with blocks that can't be loaded from the API # for artifacts with blocks that can't be loaded from the API
@ -328,18 +334,17 @@ module Cask
hash.to_h.transform_values do |value| hash.to_h.transform_values do |value|
from_h_gsubs(value, appdir) from_h_gsubs(value, appdir)
end end
rescue TypeError
from_h_array_gsubs(hash, appdir)
end end
def from_h_gsubs(value, appdir) def from_h_gsubs(value, appdir)
return value if value.blank? return value if value.blank?
if value.respond_to? :to_h case value
when Hash
from_h_hash_gsubs(value, appdir) from_h_hash_gsubs(value, appdir)
elsif value.respond_to? :to_a when Array
from_h_array_gsubs(value, appdir) from_h_array_gsubs(value, appdir)
elsif value.is_a? String when String
from_h_string_gsubs(value, appdir) from_h_string_gsubs(value, appdir)
else else
value value

View File

@ -64,7 +64,7 @@ module Cask
def fetch(quiet: nil, timeout: nil) def fetch(quiet: nil, timeout: nil)
odebug "Cask::Installer#fetch" odebug "Cask::Installer#fetch"
load_cask_from_source_api! if @cask.loaded_from_api && @cask.caskfile_only? load_cask_from_source_api! if @cask.loaded_from_api? && @cask.caskfile_only?
verify_has_sha if require_sha? && !force? verify_has_sha if require_sha? && !force?
@ -382,7 +382,7 @@ module Cask
return if @cask.source.blank? return if @cask.source.blank?
extension = @cask.loaded_from_api ? "json" : "rb" extension = @cask.loaded_from_api? ? "json" : "rb"
(metadata_subdir/"#{@cask.token}.#{extension}").write @cask.source (metadata_subdir/"#{@cask.token}.#{extension}").write @cask.source
old_savedir&.rmtree old_savedir&.rmtree
end end
@ -559,7 +559,7 @@ module Cask
end end
end end
load_cask_from_source_api! if @cask.loaded_from_api && @cask.caskfile_only? load_cask_from_source_api! if @cask.loaded_from_api? && @cask.caskfile_only?
# otherwise we default to the current cask # otherwise we default to the current cask
end end

View File

@ -66,7 +66,7 @@ describe Cask::CaskLoader::FromAPILoader, :cask do
it "loads from JSON API" do it "loads from JSON API" do
expect(cask_from_api).to be_a(Cask::Cask) expect(cask_from_api).to be_a(Cask::Cask)
expect(cask_from_api.token).to eq(cask_token) expect(cask_from_api.token).to eq(cask_token)
expect(cask_from_api.loaded_from_api).to be(true) expect(cask_from_api.loaded_from_api?).to be(true)
expect(cask_from_api.caskfile_only?).to be(caskfile_only) expect(cask_from_api.caskfile_only?).to be(caskfile_only)
end end
end end

View File

@ -244,7 +244,7 @@ describe Cask::Installer, :cask do
expect(Homebrew::API::Cask).to receive(:fetch_source).once.and_return(content) expect(Homebrew::API::Cask).to receive(:fetch_source).once.and_return(content)
caffeine = Cask::CaskLoader.load(path) caffeine = Cask::CaskLoader.load(path)
expect(caffeine).to receive(:loaded_from_api).once.and_return(true) expect(caffeine).to receive(:loaded_from_api?).once.and_return(true)
expect(caffeine).to receive(:caskfile_only?).once.and_return(true) expect(caffeine).to receive(:caskfile_only?).once.and_return(true)
described_class.new(caffeine).install described_class.new(caffeine).install
@ -299,7 +299,7 @@ describe Cask::Installer, :cask do
expect(Homebrew::API::Cask).to receive(:fetch_source).twice.and_return(content) expect(Homebrew::API::Cask).to receive(:fetch_source).twice.and_return(content)
caffeine = Cask::CaskLoader.load(path) caffeine = Cask::CaskLoader.load(path)
expect(caffeine).to receive(:loaded_from_api).twice.and_return(true) expect(caffeine).to receive(:loaded_from_api?).twice.and_return(true)
expect(caffeine).to receive(:caskfile_only?).twice.and_return(true) expect(caffeine).to receive(:caskfile_only?).twice.and_return(true)
expect(caffeine).to receive(:installed_caskfile).once.and_return(invalid_path) expect(caffeine).to receive(:installed_caskfile).once.and_return(invalid_path)