2020-10-10 14:16:11 +02:00
|
|
|
# typed: true
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-04-25 17:57:51 +01:00
|
|
|
require "tab"
|
|
|
|
|
|
|
|
module Utils
|
2020-08-19 07:50:49 +02:00
|
|
|
# Helper functions for bottles.
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
module Bottles
|
2016-04-25 17:57:51 +01:00
|
|
|
class << self
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2016-04-25 17:57:51 +01:00
|
|
|
def tag
|
2021-04-08 13:45:15 +01:00
|
|
|
@tag ||= Tag.new(system: T.must(ENV["HOMEBREW_SYSTEM"]).downcase.to_sym,
|
|
|
|
arch: T.must(ENV["HOMEBREW_PROCESSOR"]).downcase.to_sym)
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def built_as?(f)
|
2019-12-03 11:42:09 +00:00
|
|
|
return false unless f.latest_version_installed?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2020-08-21 12:10:44 -07:00
|
|
|
tab = Tab.for_keg(f.latest_installed_prefix)
|
2016-04-25 17:57:51 +01:00
|
|
|
tab.built_as_bottle
|
|
|
|
end
|
|
|
|
|
|
|
|
def file_outdated?(f, file)
|
|
|
|
filename = file.basename.to_s
|
2021-03-30 17:35:13 +01:00
|
|
|
return false if f.bottle.blank?
|
2016-04-25 17:57:51 +01:00
|
|
|
|
2021-03-30 17:35:13 +01:00
|
|
|
bottle_ext, bottle_tag, = extname_tag_rebuild(filename)
|
|
|
|
return false if bottle_ext.blank?
|
|
|
|
return false if bottle_tag != tag.to_s
|
|
|
|
|
|
|
|
bottle_url_ext, = extname_tag_rebuild(f.bottle.url)
|
2016-04-25 17:57:51 +01:00
|
|
|
|
|
|
|
bottle_ext && bottle_url_ext && bottle_ext != bottle_url_ext
|
|
|
|
end
|
|
|
|
|
2021-03-30 17:35:13 +01:00
|
|
|
def extname_tag_rebuild(filename)
|
|
|
|
HOMEBREW_BOTTLES_EXTNAME_REGEX.match(filename).to_a
|
|
|
|
end
|
|
|
|
|
2021-04-13 14:26:31 +01:00
|
|
|
def bottle_file_list(bottle_file)
|
|
|
|
@bottle_file_list ||= {}
|
|
|
|
@bottle_file_list[bottle_file] ||= Utils.popen_read("tar", "-tzf", bottle_file)
|
|
|
|
.lines
|
|
|
|
.map(&:chomp)
|
|
|
|
end
|
|
|
|
|
2016-04-25 17:57:51 +01:00
|
|
|
def receipt_path(bottle_file)
|
2021-04-13 14:26:31 +01:00
|
|
|
bottle_file_list(bottle_file).find do |line|
|
2016-07-29 15:54:56 -06:00
|
|
|
line =~ %r{.+/.+/INSTALL_RECEIPT.json}
|
|
|
|
end
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def resolve_formula_names(bottle_file)
|
2021-04-13 14:26:31 +01:00
|
|
|
name = bottle_file_list(bottle_file).first.to_s.split("/").first
|
|
|
|
full_name = if (receipt_file_path = receipt_path(bottle_file))
|
|
|
|
receipt_file = Utils.popen_read("tar", "-xOzf", bottle_file, receipt_file_path)
|
|
|
|
tap = Tab.from_file_content(receipt_file, "#{bottle_file}/#{receipt_file_path}").tap
|
|
|
|
"#{tap}/#{name}" if tap.present? && !tap.core_tap?
|
|
|
|
elsif (bottle_json_path = Pathname(bottle_file.sub(/\.tar\.gz$/, ".json"))) &&
|
|
|
|
bottle_json_path.exist? &&
|
|
|
|
(bottle_json_path_contents = bottle_json_path.read.presence) &&
|
|
|
|
(bottle_json = JSON.parse(bottle_json_path_contents).presence) &&
|
|
|
|
bottle_json.is_a?(Hash)
|
|
|
|
bottle_json.keys.first.presence
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
2021-04-13 14:26:31 +01:00
|
|
|
full_name ||= name
|
2016-04-25 17:57:51 +01:00
|
|
|
|
|
|
|
[name, full_name]
|
|
|
|
end
|
|
|
|
|
|
|
|
def resolve_version(bottle_file)
|
2021-04-13 14:26:31 +01:00
|
|
|
version = bottle_file_list(bottle_file).first.to_s.split("/").second
|
|
|
|
PkgVersion.parse(version)
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
2017-09-25 22:46:51 -07:00
|
|
|
|
|
|
|
def formula_contents(bottle_file,
|
2019-04-30 08:44:35 +01:00
|
|
|
name: resolve_formula_names(bottle_file)[0])
|
2017-09-25 22:46:51 -07:00
|
|
|
bottle_version = resolve_version bottle_file
|
|
|
|
formula_path = "#{name}/#{bottle_version}/.brew/#{name}.rb"
|
|
|
|
contents = Utils.popen_read "tar", "-xOzf", bottle_file, formula_path
|
|
|
|
raise BottleFormulaUnavailableError.new(bottle_file, formula_path) unless $CHILD_STATUS.success?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2017-09-25 22:46:51 -07:00
|
|
|
contents
|
|
|
|
end
|
2021-04-15 18:06:54 +01:00
|
|
|
|
|
|
|
def path_resolved_basename(root_url, name, checksum, filename)
|
|
|
|
if root_url.match?(GitHubPackages::URL_REGEX)
|
|
|
|
image_name = GitHubPackages.image_formula_name(name)
|
|
|
|
["#{image_name}/blobs/sha256:#{checksum}", filename&.github_packages]
|
|
|
|
else
|
|
|
|
filename&.url_encode
|
|
|
|
end
|
|
|
|
end
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
|
|
|
|
2021-04-08 13:45:15 +01:00
|
|
|
# Denotes the arch and OS of a bottle.
|
|
|
|
class Tag
|
|
|
|
extend T::Sig
|
|
|
|
|
|
|
|
attr_reader :system, :arch
|
|
|
|
|
|
|
|
sig { params(value: Symbol).returns(T.attached_class) }
|
|
|
|
def self.from_symbol(value)
|
2021-04-08 17:39:57 +01:00
|
|
|
return new(system: :all, arch: :all) if value == :all
|
|
|
|
|
2021-04-08 13:45:15 +01:00
|
|
|
@all_archs_regex ||= begin
|
|
|
|
all_archs = Hardware::CPU::ALL_ARCHS.map(&:to_s)
|
|
|
|
/
|
|
|
|
^((?<arch>#{Regexp.union(all_archs)})_)?
|
|
|
|
(?<system>[\w.]+)$
|
|
|
|
/x
|
|
|
|
end
|
|
|
|
match = @all_archs_regex.match(value.to_s)
|
|
|
|
raise ArgumentError, "Invalid bottle tag symbol" unless match
|
|
|
|
|
|
|
|
system = match[:system].to_sym
|
|
|
|
arch = match[:arch]&.to_sym || :x86_64
|
|
|
|
new(system: system, arch: arch)
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(system: Symbol, arch: Symbol).void }
|
|
|
|
def initialize(system:, arch:)
|
|
|
|
@system = system
|
|
|
|
@arch = arch
|
|
|
|
end
|
|
|
|
|
|
|
|
def ==(other)
|
|
|
|
if other.is_a?(Symbol)
|
|
|
|
to_sym == other
|
|
|
|
else
|
|
|
|
self.class == other.class && system == other.system && arch == other.arch
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(Symbol) }
|
|
|
|
def to_sym
|
2021-04-08 17:39:57 +01:00
|
|
|
if system == :all && arch == :all
|
|
|
|
:all
|
|
|
|
elsif macos? && arch == :x86_64
|
2021-04-08 13:45:15 +01:00
|
|
|
system
|
|
|
|
else
|
|
|
|
"#{arch}_#{system}".to_sym
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(String) }
|
|
|
|
def to_s
|
|
|
|
to_sym.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(OS::Mac::Version) }
|
|
|
|
def to_macos_version
|
|
|
|
@to_macos_version ||= OS::Mac::Version.from_symbol(system)
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def linux?
|
|
|
|
system == :linux
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def macos?
|
|
|
|
to_macos_version
|
|
|
|
true
|
|
|
|
rescue MacOSVersionError
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(String) }
|
|
|
|
def default_prefix
|
|
|
|
if linux?
|
|
|
|
HOMEBREW_LINUX_DEFAULT_PREFIX
|
|
|
|
elsif arch == :arm64
|
|
|
|
HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
|
|
|
|
else
|
|
|
|
HOMEBREW_DEFAULT_PREFIX
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(String) }
|
|
|
|
def default_cellar
|
|
|
|
if linux?
|
|
|
|
Homebrew::DEFAULT_LINUX_CELLAR
|
|
|
|
elsif arch == :arm64
|
|
|
|
Homebrew::DEFAULT_MACOS_ARM_CELLAR
|
|
|
|
else
|
|
|
|
Homebrew::DEFAULT_MACOS_CELLAR
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-08-19 07:50:49 +02:00
|
|
|
# Helper functions for bottles hosted on Bintray.
|
|
|
|
module Bintray
|
2016-04-25 17:57:51 +01:00
|
|
|
def self.package(formula_name)
|
2016-08-28 23:55:43 +01:00
|
|
|
package_name = formula_name.to_s.dup
|
|
|
|
package_name.tr!("+", "x")
|
|
|
|
package_name.sub!(/(.)@(\d)/, "\\1:\\2") # Handle foo@1.2 style formulae.
|
|
|
|
package_name
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.repository(tap = nil)
|
|
|
|
if tap.nil? || tap.core_tap?
|
|
|
|
"bottles"
|
|
|
|
else
|
|
|
|
"bottles-#{tap.repo}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Collector for bottle specifications.
|
2016-04-25 17:57:51 +01:00
|
|
|
class Collector
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2020-02-19 11:54:42 +00:00
|
|
|
extend Forwardable
|
|
|
|
|
2020-11-29 17:51:47 +01:00
|
|
|
def_delegators :@checksums, :keys, :[], :[]=, :key?, :each_key, :dig
|
2020-02-19 11:54:42 +00:00
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { void }
|
2016-04-25 17:57:51 +01:00
|
|
|
def initialize
|
|
|
|
@checksums = {}
|
|
|
|
end
|
|
|
|
|
2021-04-08 13:45:15 +01:00
|
|
|
sig {
|
|
|
|
params(
|
2021-04-08 14:58:39 +01:00
|
|
|
tag: T.any(Symbol, Utils::Bottles::Tag),
|
|
|
|
no_older_versions: T::Boolean,
|
2021-04-08 13:45:15 +01:00
|
|
|
).returns(
|
|
|
|
T.nilable([Checksum, Symbol, T.any(Symbol, String)]),
|
|
|
|
)
|
|
|
|
}
|
2021-04-08 14:58:39 +01:00
|
|
|
def fetch_checksum_for(tag, no_older_versions: false)
|
2021-04-08 13:45:15 +01:00
|
|
|
tag = Utils::Bottles::Tag.from_symbol(tag) if tag.is_a?(Symbol)
|
2021-04-08 14:58:39 +01:00
|
|
|
tag = find_matching_tag(tag, no_older_versions: no_older_versions)&.to_sym
|
2020-11-29 17:51:47 +01:00
|
|
|
return self[tag][:checksum], tag, self[tag][:cellar] if tag
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2021-04-08 14:58:39 +01:00
|
|
|
def find_matching_tag(tag, no_older_versions: false)
|
2021-04-08 17:39:57 +01:00
|
|
|
if key?(tag.to_sym)
|
|
|
|
tag
|
|
|
|
elsif key?(:all)
|
|
|
|
Tag.from_symbol(:all)
|
|
|
|
end
|
2016-04-25 17:57:51 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
require "extend/os/bottles"
|