Overhaul Formula/Cask JSON generation
- Use constants for placeholders - Monkeypatch to set `HOMEBREW_PREFIX` consistently to placeholder - Use environment variable to set `Dir.home` consistently to placeholder - Use `appdir` short-circuit to set `Cask#appdir` consistently to placeholder - Use `Cask.generating_hash!` to enable "generating mode" with these patches - Fix `Formula#caveats` from JSON Fixes #14505 Fixes #14595
This commit is contained in:
parent
66c9d5f2af
commit
237eec8ef8
@ -19,10 +19,48 @@ module Cask
|
|||||||
extend Searchable
|
extend Searchable
|
||||||
include Metadata
|
include Metadata
|
||||||
|
|
||||||
attr_reader :token, :sourcefile_path, :source, :config, :default_config, :loaded_from_api
|
HOME_PLACEHOLDER = "$HOME"
|
||||||
|
HOMEBREW_PREFIX_PLACEHOLDER = "$HOMEBREW_PREFIX"
|
||||||
|
APPDIR_PLACEHOLDER = "$APPDIR"
|
||||||
|
|
||||||
|
# TODO: can be removed when API JSON is regenerated with HOMEBREW_PREFIX_PLACEHOLDER.
|
||||||
|
HOMEBREW_OLD_PREFIX_PLACEHOLDER = "$(brew --prefix)"
|
||||||
|
|
||||||
|
attr_reader :token, :sourcefile_path, :source, :config, :default_config, :loaded_from_api, :loader
|
||||||
|
|
||||||
attr_accessor :download, :allow_reassignment
|
attr_accessor :download, :allow_reassignment
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def generating_hash!
|
||||||
|
return if generating_hash?
|
||||||
|
|
||||||
|
# Apply monkeypatches for API generation
|
||||||
|
@old_homebrew_prefix = HOMEBREW_PREFIX
|
||||||
|
@old_home = Dir.home
|
||||||
|
Object.send(:remove_const, :HOMEBREW_PREFIX)
|
||||||
|
Object.const_set(:HOMEBREW_PREFIX, Pathname(HOMEBREW_PREFIX_PLACEHOLDER))
|
||||||
|
ENV["HOME"] = HOME_PLACEHOLDER
|
||||||
|
|
||||||
|
@generating_hash = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def generated_hash!
|
||||||
|
return unless generating_hash?
|
||||||
|
|
||||||
|
# Revert monkeypatches for API generation
|
||||||
|
Object.send(:remove_const, :HOMEBREW_PREFIX)
|
||||||
|
Object.const_set(:HOMEBREW_PREFIX, @old_homebrew_prefix)
|
||||||
|
ENV["HOME"] = @old_home
|
||||||
|
|
||||||
|
@generating_hash = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def generating_hash?
|
||||||
|
@generating_hash ||= false
|
||||||
|
@generating_hash == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.all
|
def self.all
|
||||||
# TODO: ideally avoid using ARGV by moving to e.g. CLI::Parser
|
# TODO: ideally avoid using ARGV by moving to e.g. CLI::Parser
|
||||||
if ARGV.exclude?("--eval-all") && !Homebrew::EnvConfig.eval_all?
|
if ARGV.exclude?("--eval-all") && !Homebrew::EnvConfig.eval_all?
|
||||||
@ -45,13 +83,14 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
def initialize(token, sourcefile_path: nil, source: nil, tap: nil, config: nil,
|
def initialize(token, sourcefile_path: nil, source: nil, tap: nil, config: nil,
|
||||||
allow_reassignment: false, loaded_from_api: false, &block)
|
allow_reassignment: false, loaded_from_api: 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 = loaded_from_api
|
@loaded_from_api = loaded_from_api
|
||||||
|
@loader = loader
|
||||||
@block = block
|
@block = block
|
||||||
|
|
||||||
@default_config = config || Config.new
|
@default_config = config || Config.new
|
||||||
@ -251,7 +290,7 @@ module Cask
|
|||||||
"outdated" => outdated?,
|
"outdated" => outdated?,
|
||||||
"sha256" => sha256,
|
"sha256" => sha256,
|
||||||
"artifacts" => artifacts_list,
|
"artifacts" => artifacts_list,
|
||||||
"caveats" => (to_h_string_gsubs(caveats) unless caveats.empty?),
|
"caveats" => (caveats unless caveats.empty?),
|
||||||
"depends_on" => depends_on,
|
"depends_on" => depends_on,
|
||||||
"conflicts_with" => conflicts_with,
|
"conflicts_with" => conflicts_with,
|
||||||
"container" => container&.pairs,
|
"container" => container&.pairs,
|
||||||
@ -315,52 +354,10 @@ module Cask
|
|||||||
when Artifact::AbstractFlightBlock
|
when Artifact::AbstractFlightBlock
|
||||||
# Only indicate whether this block is used as we don't load it from the API
|
# Only indicate whether this block is used as we don't load it from the API
|
||||||
{ artifact.summarize => nil }
|
{ artifact.summarize => nil }
|
||||||
when Artifact::Relocated
|
|
||||||
# Don't replace the Homebrew prefix in the source path since the source could include /usr/local
|
|
||||||
source, *args = artifact.to_args
|
|
||||||
{ artifact.class.dsl_key => [to_h_string_gsubs(source, replace_prefix: false), *to_h_gsubs(args)] }
|
|
||||||
else
|
else
|
||||||
{ artifact.class.dsl_key => to_h_gsubs(artifact.to_args) }
|
{ artifact.class.dsl_key => artifact.to_args }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h_string_gsubs(string, replace_prefix: true)
|
|
||||||
string = string.to_s.gsub(Dir.home, "$HOME")
|
|
||||||
|
|
||||||
if replace_prefix
|
|
||||||
string.gsub(HOMEBREW_PREFIX, "$(brew --prefix)")
|
|
||||||
else
|
|
||||||
string.gsub(Caskroom.path, "$(brew --prefix)/Caskroom")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_h_array_gsubs(array)
|
|
||||||
array.to_a.map do |value|
|
|
||||||
to_h_gsubs(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_h_hash_gsubs(hash)
|
|
||||||
hash.to_h.transform_values do |value|
|
|
||||||
to_h_gsubs(value)
|
|
||||||
end
|
|
||||||
rescue TypeError
|
|
||||||
to_h_array_gsubs(hash)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_h_gsubs(value)
|
|
||||||
return value if value.blank?
|
|
||||||
|
|
||||||
if value.respond_to? :to_h
|
|
||||||
to_h_hash_gsubs(value)
|
|
||||||
elsif value.respond_to? :to_a
|
|
||||||
to_h_array_gsubs(value)
|
|
||||||
elsif [true, false].include? value
|
|
||||||
value
|
|
||||||
else
|
|
||||||
to_h_string_gsubs(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -237,13 +237,9 @@ module Cask
|
|||||||
return FromContentLoader.new(cask_source).load(config: config)
|
return FromContentLoader.new(cask_source).load(config: config)
|
||||||
end
|
end
|
||||||
|
|
||||||
# convert generic string replacements into actual ones
|
|
||||||
json_cask[:artifacts] = json_cask[:artifacts].map(&method(:from_h_hash_gsubs))
|
|
||||||
json_cask[:caveats] = from_h_string_gsubs(json_cask[:caveats])
|
|
||||||
|
|
||||||
tap = Tap.fetch(json_cask[:tap]) if json_cask[:tap].to_s.include?("/")
|
tap = Tap.fetch(json_cask[:tap]) if json_cask[:tap].to_s.include?("/")
|
||||||
|
|
||||||
Cask.new(token, tap: tap, source: cask_source, config: config, loaded_from_api: true) do
|
Cask.new(token, tap: tap, source: cask_source, config: config, loaded_from_api: true, loader: self) do
|
||||||
version json_cask[:version]
|
version json_cask[:version]
|
||||||
|
|
||||||
if json_cask[:sha256] == "no_check"
|
if json_cask[:sha256] == "no_check"
|
||||||
@ -300,45 +296,53 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
json_cask[:artifacts].each do |artifact|
|
json_cask[:artifacts].each do |artifact|
|
||||||
|
# convert generic string replacements into actual ones
|
||||||
|
artifact = cask.loader.from_h_hash_gsubs(artifact, appdir)
|
||||||
key = artifact.keys.first
|
key = artifact.keys.first
|
||||||
send(key, *artifact[key])
|
send(key, *artifact[key])
|
||||||
end
|
end
|
||||||
|
|
||||||
caveats json_cask[:caveats] if json_cask[:caveats].present?
|
if json_cask[:caveats].present?
|
||||||
|
# convert generic string replacements into actual ones
|
||||||
|
json_cask[:caveats] = cask.loader.from_h_string_gsubs(json_cask[:caveats], appdir)
|
||||||
|
caveats json_cask[:caveats]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def from_h_string_gsubs(string, appdir)
|
||||||
|
# TODO: HOMEBREW_OLD_PREFIX_PLACEHOLDER can be removed when API JSON is
|
||||||
def from_h_string_gsubs(string)
|
# regenerated with HOMEBREW_PREFIX_PLACEHOLDER.
|
||||||
string.to_s
|
string.to_s
|
||||||
.gsub("$HOME", Dir.home)
|
.gsub(Cask::HOME_PLACEHOLDER, Dir.home)
|
||||||
.gsub("$(brew --prefix)", HOMEBREW_PREFIX)
|
.gsub(Cask::HOMEBREW_PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
|
||||||
|
.gsub(Cask::APPDIR_PLACEHOLDER, appdir)
|
||||||
|
.gsub(Cask::HOMEBREW_OLD_PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
|
||||||
end
|
end
|
||||||
|
|
||||||
def from_h_array_gsubs(array)
|
def from_h_array_gsubs(array, appdir)
|
||||||
array.to_a.map do |value|
|
array.to_a.map do |value|
|
||||||
from_h_gsubs(value)
|
from_h_gsubs(value, appdir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def from_h_hash_gsubs(hash)
|
def from_h_hash_gsubs(hash, appdir)
|
||||||
hash.to_h.transform_values do |value|
|
hash.to_h.transform_values do |value|
|
||||||
from_h_gsubs(value)
|
from_h_gsubs(value, appdir)
|
||||||
end
|
end
|
||||||
rescue TypeError
|
rescue TypeError
|
||||||
from_h_array_gsubs(hash)
|
from_h_array_gsubs(hash, appdir)
|
||||||
end
|
end
|
||||||
|
|
||||||
def from_h_gsubs(value)
|
def from_h_gsubs(value, appdir)
|
||||||
return value if value.blank?
|
return value if value.blank?
|
||||||
|
|
||||||
if value.respond_to? :to_h
|
if value.respond_to? :to_h
|
||||||
from_h_hash_gsubs(value)
|
from_h_hash_gsubs(value, appdir)
|
||||||
elsif value.respond_to? :to_a
|
elsif value.respond_to? :to_a
|
||||||
from_h_array_gsubs(value)
|
from_h_array_gsubs(value, appdir)
|
||||||
elsif value.is_a? String
|
elsif value.is_a? String
|
||||||
from_h_string_gsubs(value)
|
from_h_string_gsubs(value, appdir)
|
||||||
else
|
else
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
@ -376,6 +376,8 @@ module Cask
|
|||||||
|
|
||||||
# @api public
|
# @api public
|
||||||
def appdir
|
def appdir
|
||||||
|
return Cask::APPDIR_PLACEHOLDER if Cask.generating_hash?
|
||||||
|
|
||||||
cask.config.appdir
|
cask.config.appdir
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2119,7 +2119,7 @@ class Formula
|
|||||||
"uses_from_macos" => uses_from_macos_elements.uniq,
|
"uses_from_macos" => uses_from_macos_elements.uniq,
|
||||||
"requirements" => [],
|
"requirements" => [],
|
||||||
"conflicts_with" => conflicts.map(&:name),
|
"conflicts_with" => conflicts.map(&:name),
|
||||||
"caveats" => caveats&.gsub(HOMEBREW_PREFIX, "$(brew --prefix)"),
|
"caveats" => caveats&.gsub(HOMEBREW_PREFIX, HOMEBREW_PREFIX_PLACEHOLDER),
|
||||||
"installed" => [],
|
"installed" => [],
|
||||||
"linked_keg" => linked_version&.to_s,
|
"linked_keg" => linked_version&.to_s,
|
||||||
"pinned" => pinned?,
|
"pinned" => pinned?,
|
||||||
|
@ -251,6 +251,7 @@ module Formulary
|
|||||||
@caveats_string = json_formula["caveats"]
|
@caveats_string = json_formula["caveats"]
|
||||||
def caveats
|
def caveats
|
||||||
self.class.instance_variable_get(:@caveats_string)
|
self.class.instance_variable_get(:@caveats_string)
|
||||||
|
&.gsub(HOMEBREW_PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tap_git_head_string = json_formula["tap_git_head"]
|
@tap_git_head_string = json_formula["tap_git_head"]
|
||||||
|
@ -64,6 +64,7 @@ HOMEBREW_MACOS_ARM_DEFAULT_PREFIX = "/opt/homebrew"
|
|||||||
HOMEBREW_MACOS_ARM_DEFAULT_REPOSITORY = HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
|
HOMEBREW_MACOS_ARM_DEFAULT_REPOSITORY = HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
|
||||||
HOMEBREW_LINUX_DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew"
|
HOMEBREW_LINUX_DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew"
|
||||||
HOMEBREW_LINUX_DEFAULT_REPOSITORY = "#{HOMEBREW_LINUX_DEFAULT_PREFIX}/Homebrew"
|
HOMEBREW_LINUX_DEFAULT_REPOSITORY = "#{HOMEBREW_LINUX_DEFAULT_PREFIX}/Homebrew"
|
||||||
|
HOMEBREW_PREFIX_PLACEHOLDER = "$HOMEBREW_PREFIX"
|
||||||
|
|
||||||
HOMEBREW_PULL_API_REGEX =
|
HOMEBREW_PULL_API_REGEX =
|
||||||
%r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
|
%r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
|
||||||
|
@ -300,5 +300,18 @@ describe Cask::Cask, :cask do
|
|||||||
expect(h).to be_a(Hash)
|
expect(h).to be_a(Hash)
|
||||||
expect(JSON.pretty_generate(h["variations"])).to eq expected_sha256_variations.strip
|
expect(JSON.pretty_generate(h["variations"])).to eq expected_sha256_variations.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns the correct hash placeholders" do
|
||||||
|
described_class.generating_hash!
|
||||||
|
expect(described_class).to be_generating_hash
|
||||||
|
c = Cask::CaskLoader.load("placeholders")
|
||||||
|
h = c.to_hash_with_variations
|
||||||
|
described_class.generated_hash!
|
||||||
|
expect(described_class).not_to be_generating_hash
|
||||||
|
|
||||||
|
expect(h).to be_a(Hash)
|
||||||
|
expect(h["artifacts"].first[:binary].first).to eq "$APPDIR/some/path"
|
||||||
|
expect(h["caveats"]).to eq "$HOMEBREW_PREFIX and $HOME\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -117,7 +117,7 @@ describe Cask::Cmd::List, :cask do
|
|||||||
{
|
{
|
||||||
"zap": [
|
"zap": [
|
||||||
{
|
{
|
||||||
"trash": "$HOME/support/fixtures/cask/caffeine/org.example.caffeine.plist"
|
"trash": "#{TEST_FIXTURE_DIR}/cask/caffeine/org.example.caffeine.plist"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
cask "placeholders" do
|
||||||
|
version "2.61"
|
||||||
|
sha256 "e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68"
|
||||||
|
|
||||||
|
url "file://#{TEST_FIXTURE_DIR}/cask/transmission-2.61.dmg"
|
||||||
|
homepage "https://brew.sh/placeholders"
|
||||||
|
|
||||||
|
binary "#{appdir}/some/path"
|
||||||
|
|
||||||
|
caveats "#{HOMEBREW_PREFIX} and #{Dir.home}"
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user