brew/Library/Homebrew/utils/bottles.rb

229 lines
5.9 KiB
Ruby
Raw Normal View History

2020-10-10 14:16:11 +02:00
# typed: true
# 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
@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)
return false unless f.latest_version_installed?
2018-09-17 02:45:00 +02: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
return false if f.bottle.blank?
2016-04-25 17:57:51 +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
def extname_tag_rebuild(filename)
HOMEBREW_BOTTLES_EXTNAME_REGEX.match(filename).to_a
end
2016-04-25 17:57:51 +01:00
def receipt_path(bottle_file)
path = Utils.popen_read("tar", "-tzf", bottle_file).lines.map(&:chomp).find do |line|
line =~ %r{.+/.+/INSTALL_RECEIPT.json}
end
raise "This bottle does not contain the file INSTALL_RECEIPT.json: #{bottle_file}" unless path
2018-09-17 02:45:00 +02:00
path
2016-04-25 17:57:51 +01:00
end
def resolve_formula_names(bottle_file)
receipt_file_path = receipt_path bottle_file
receipt_file = Utils.popen_read("tar", "-xOzf", bottle_file, receipt_file_path)
name = receipt_file_path.split("/").first
tap = Tab.from_file_content(receipt_file, "#{bottle_file}/#{receipt_file_path}").tap
2020-03-13 21:15:06 +00:00
full_name = if tap.nil? || tap.core_tap?
name
2016-04-25 17:57:51 +01:00
else
2020-03-13 21:15:06 +00:00
"#{tap}/#{name}"
2016-04-25 17:57:51 +01:00
end
[name, full_name]
end
def resolve_version(bottle_file)
2018-09-17 19:44:12 +02:00
PkgVersion.parse receipt_path(bottle_file).split("/").second
2016-04-25 17:57:51 +01:00
end
def formula_contents(bottle_file,
2019-04-30 08:44:35 +01:00
name: resolve_formula_names(bottle_file)[0])
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
contents
end
2016-04-25 17:57:51 +01:00
end
# 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)
@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
if macos? && arch == :x86_64
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
# 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
sig {
params(
tag: T.any(Symbol, Utils::Bottles::Tag),
no_older_versions: T::Boolean,
).returns(
T.nilable([Checksum, Symbol, T.any(Symbol, String)]),
)
}
def fetch_checksum_for(tag, no_older_versions: false)
tag = Utils::Bottles::Tag.from_symbol(tag) if tag.is_a?(Symbol)
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
def find_matching_tag(tag, no_older_versions: false)
tag if key?(tag.to_sym)
2016-04-25 17:57:51 +01:00
end
end
end
end
require "extend/os/bottles"