2024-08-12 10:30:59 +01:00
|
|
|
|
# typed: true # rubocop:todo Sorbet/StrictSigil
|
2019-04-19 15:38:03 +09:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
|
require "downloadable"
|
2018-07-13 14:42:49 +01:00
|
|
|
|
require "mktemp"
|
2022-06-30 16:08:13 +02:00
|
|
|
|
require "livecheck"
|
2025-06-09 19:06:16 +01:00
|
|
|
|
require "on_system"
|
2013-09-17 21:25:38 -05:00
|
|
|
|
|
2013-09-17 21:25:38 -05:00
|
|
|
|
# Resource is the fundamental representation of an external resource. The
|
|
|
|
|
# primary formula download, along with other declared resources, are instances
|
|
|
|
|
# of this class.
|
2024-07-14 21:03:08 -04:00
|
|
|
|
class Resource
|
|
|
|
|
include Downloadable
|
2013-08-06 19:52:58 -07:00
|
|
|
|
include FileUtils
|
2022-06-29 17:48:21 -04:00
|
|
|
|
include OnSystem::MacOSAndLinux
|
2013-08-06 19:52:58 -07:00
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
|
attr_reader :source_modified_time, :patches, :owner
|
|
|
|
|
attr_writer :checksum
|
|
|
|
|
attr_accessor :download_strategy
|
2013-09-17 21:25:38 -05:00
|
|
|
|
|
2013-09-17 21:25:38 -05:00
|
|
|
|
# Formula name must be set after the DSL, as we have no access to the
|
2020-11-05 17:17:03 -05:00
|
|
|
|
# formula name before initialization of the formula.
|
2018-01-21 08:29:38 -08:00
|
|
|
|
attr_accessor :name
|
2013-09-17 21:25:38 -05:00
|
|
|
|
|
2023-03-25 08:36:56 -07:00
|
|
|
|
sig { params(name: T.nilable(String), block: T.nilable(T.proc.bind(Resource).void)).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
|
def initialize(name = nil, &block)
|
2023-04-18 00:22:13 +01:00
|
|
|
|
super()
|
2025-04-23 03:30:15 +01:00
|
|
|
|
# Generally ensure this is synced with `initialize_dup` and `freeze`
|
|
|
|
|
# (excluding simple objects like integers & booleans, weak refs like `owner` or permafrozen objects)
|
2013-08-06 19:52:58 -07:00
|
|
|
|
@name = name
|
2025-04-23 03:30:15 +01:00
|
|
|
|
@source_modified_time = nil
|
2018-01-21 08:29:38 -08:00
|
|
|
|
@patches = []
|
2025-04-23 03:30:15 +01:00
|
|
|
|
@owner = nil
|
2022-08-24 23:53:35 +01:00
|
|
|
|
@livecheck = Livecheck.new(self)
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
|
@livecheck_defined = false
|
2023-04-18 00:22:13 +01:00
|
|
|
|
@insecure = false
|
2020-11-16 22:18:56 +01:00
|
|
|
|
instance_eval(&block) if block
|
2013-08-06 19:52:58 -07:00
|
|
|
|
end
|
|
|
|
|
|
2025-04-23 03:30:15 +01:00
|
|
|
|
sig { params(other: Object).void }
|
2022-08-24 23:53:35 +01:00
|
|
|
|
def initialize_dup(other)
|
|
|
|
|
super
|
|
|
|
|
@name = @name.dup
|
|
|
|
|
@patches = @patches.dup
|
|
|
|
|
@livecheck = @livecheck.dup
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def freeze
|
|
|
|
|
@name.freeze
|
|
|
|
|
@patches.freeze
|
|
|
|
|
@livecheck.freeze
|
|
|
|
|
super
|
|
|
|
|
end
|
|
|
|
|
|
2018-01-21 08:29:38 -08:00
|
|
|
|
def owner=(owner)
|
|
|
|
|
@owner = owner
|
|
|
|
|
patches.each { |p| p.owner = owner }
|
2013-08-06 19:52:58 -07:00
|
|
|
|
end
|
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
|
# Removes /s from resource names; this allows Go package names
|
2014-06-02 21:53:53 -07:00
|
|
|
|
# to be used as resource names without confusing software that
|
2020-11-05 17:17:03 -05:00
|
|
|
|
# interacts with {download_name}, e.g. `github.com/foo/bar`.
|
2014-06-02 21:53:53 -07:00
|
|
|
|
def escaped_name
|
2015-08-06 15:45:52 +08:00
|
|
|
|
name.tr("/", "-")
|
2014-06-02 21:53:53 -07:00
|
|
|
|
end
|
|
|
|
|
|
2013-09-17 21:25:40 -05:00
|
|
|
|
def download_name
|
2018-08-01 05:33:03 +02:00
|
|
|
|
return owner.name if name.nil?
|
|
|
|
|
return escaped_name if owner.nil?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
|
2018-08-01 05:33:03 +02:00
|
|
|
|
"#{owner.name}--#{escaped_name}"
|
2013-09-17 21:25:40 -05:00
|
|
|
|
end
|
|
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
|
# Verifies download and unpacks it.
|
2020-08-19 06:58:36 +02:00
|
|
|
|
# The block may call `|resource, staging| staging.retain!` to retain the staging
|
2016-04-10 22:53:56 -04:00
|
|
|
|
# directory. Subclasses that override stage should implement the tmp
|
2018-10-18 21:42:43 -04:00
|
|
|
|
# dir using {Mktemp} so that works with all subtypes.
|
2020-08-19 06:58:36 +02:00
|
|
|
|
#
|
|
|
|
|
# @api public
|
2022-07-31 19:59:25 +01:00
|
|
|
|
def stage(target = nil, debug_symbols: false, &block)
|
2025-02-22 21:51:41 -08:00
|
|
|
|
raise ArgumentError, "Target directory or block is required" if !target && !block_given?
|
2014-12-13 22:51:21 -05:00
|
|
|
|
|
2020-05-13 11:49:17 +01:00
|
|
|
|
prepare_patches
|
2020-08-02 14:32:31 +02:00
|
|
|
|
fetch_patches(skip_downloaded: true)
|
|
|
|
|
fetch unless downloaded?
|
2020-03-04 17:48:17 -05:00
|
|
|
|
|
2024-03-07 16:20:20 +00:00
|
|
|
|
unpack(target, debug_symbols:, &block)
|
2013-10-30 00:43:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
2020-05-13 11:49:17 +01:00
|
|
|
|
def prepare_patches
|
2018-01-21 08:29:38 -08:00
|
|
|
|
patches.grep(DATAPatch) { |p| p.path = owner.owner.path }
|
2020-05-13 11:49:17 +01:00
|
|
|
|
end
|
|
|
|
|
|
2020-08-02 14:32:31 +02:00
|
|
|
|
def fetch_patches(skip_downloaded: false)
|
2020-05-14 09:20:58 +01:00
|
|
|
|
external_patches = patches.select(&:external?)
|
|
|
|
|
external_patches.reject!(&:downloaded?) if skip_downloaded
|
2020-08-02 14:32:31 +02:00
|
|
|
|
external_patches.each(&:fetch)
|
2018-01-21 08:29:38 -08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def apply_patches
|
|
|
|
|
return if patches.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
|
2018-01-21 08:29:38 -08:00
|
|
|
|
ohai "Patching #{name}"
|
|
|
|
|
patches.each(&:apply)
|
|
|
|
|
end
|
|
|
|
|
|
2016-04-10 22:53:56 -04:00
|
|
|
|
# If a target is given, unpack there; else unpack to a temp folder.
|
2018-10-18 21:42:43 -04:00
|
|
|
|
# If block is given, yield to that block with `|stage|`, where stage
|
|
|
|
|
# is a {ResourceStageContext}.
|
2016-04-10 22:53:56 -04:00
|
|
|
|
# A target or a block must be given, but not both.
|
2022-07-31 19:59:25 +01:00
|
|
|
|
def unpack(target = nil, debug_symbols: false)
|
2022-07-10 01:27:21 +08:00
|
|
|
|
current_working_directory = Pathname.pwd
|
2024-03-07 16:20:20 +00:00
|
|
|
|
stage_resource(download_name, debug_symbols:) do |staging|
|
2021-02-12 11:10:18 -05:00
|
|
|
|
downloader.stage do
|
2025-04-23 03:30:15 +01:00
|
|
|
|
@source_modified_time = downloader.source_modified_time.freeze
|
2021-02-12 11:10:18 -05:00
|
|
|
|
apply_patches
|
|
|
|
|
if block_given?
|
|
|
|
|
yield ResourceStageContext.new(self, staging)
|
|
|
|
|
elsif target
|
|
|
|
|
target = Pathname(target)
|
2022-07-10 01:27:21 +08:00
|
|
|
|
target = current_working_directory/target if target.relative?
|
2021-02-12 11:10:18 -05:00
|
|
|
|
target.install Pathname.pwd.children
|
|
|
|
|
end
|
2013-08-06 19:52:58 -07:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2013-09-17 21:25:43 -05:00
|
|
|
|
Partial = Struct.new(:resource, :files)
|
|
|
|
|
|
|
|
|
|
def files(*files)
|
|
|
|
|
Partial.new(self, files)
|
|
|
|
|
end
|
|
|
|
|
|
2024-07-14 11:42:22 -04:00
|
|
|
|
sig {
|
|
|
|
|
override
|
|
|
|
|
.params(
|
|
|
|
|
verify_download_integrity: T::Boolean,
|
|
|
|
|
timeout: T.nilable(T.any(Integer, Float)),
|
|
|
|
|
quiet: T::Boolean,
|
|
|
|
|
).returns(Pathname)
|
|
|
|
|
}
|
|
|
|
|
def fetch(verify_download_integrity: true, timeout: nil, quiet: false)
|
2020-08-02 14:32:31 +02:00
|
|
|
|
fetch_patches
|
2020-05-12 12:37:54 +01:00
|
|
|
|
|
2024-05-23 17:08:41 +01:00
|
|
|
|
super
|
2013-09-17 21:25:38 -05:00
|
|
|
|
end
|
|
|
|
|
|
2022-06-30 16:08:13 +02:00
|
|
|
|
# {Livecheck} can be used to check for newer versions of the software.
|
2024-12-02 10:06:14 -05:00
|
|
|
|
# This method evaluates the DSL specified in the `livecheck` block of the
|
2022-06-30 16:08:13 +02:00
|
|
|
|
# {Resource} (if it exists) and sets the instance variables of a {Livecheck}
|
|
|
|
|
# object accordingly. This is used by `brew livecheck` to check for newer
|
|
|
|
|
# versions of the software.
|
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
|
# ### Example
|
|
|
|
|
#
|
|
|
|
|
# ```ruby
|
|
|
|
|
# livecheck do
|
2022-06-30 16:08:13 +02:00
|
|
|
|
# url "https://example.com/foo/releases"
|
|
|
|
|
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
2024-04-26 20:55:51 +02:00
|
|
|
|
# end
|
|
|
|
|
# ```
|
2022-06-30 16:08:13 +02:00
|
|
|
|
def livecheck(&block)
|
|
|
|
|
return @livecheck unless block
|
|
|
|
|
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
|
@livecheck_defined = true
|
2022-06-30 16:08:13 +02:00
|
|
|
|
@livecheck.instance_eval(&block)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Whether a livecheck specification is defined or not.
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
|
#
|
|
|
|
|
# It returns `true` when a `livecheck` block is present in the {Resource}
|
|
|
|
|
# and `false` otherwise.
|
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
|
def livecheck_defined?
|
|
|
|
|
@livecheck_defined == true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Whether a livecheck specification is defined or not. This is a legacy alias
|
|
|
|
|
# for `#livecheck_defined?`.
|
|
|
|
|
#
|
|
|
|
|
# It returns `true` when a `livecheck` block is present in the {Resource}
|
|
|
|
|
# and `false` otherwise.
|
|
|
|
|
sig { returns(T::Boolean) }
|
2022-06-30 16:08:13 +02:00
|
|
|
|
def livecheckable?
|
2025-04-22 17:15:23 +01:00
|
|
|
|
odeprecated "`livecheckable?`", "`livecheck_defined?`"
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
|
@livecheck_defined == true
|
2022-06-30 16:08:13 +02:00
|
|
|
|
end
|
|
|
|
|
|
2021-01-07 08:33:57 +01:00
|
|
|
|
def sha256(val)
|
|
|
|
|
@checksum = Checksum.new(val)
|
2013-09-17 21:25:38 -05:00
|
|
|
|
end
|
|
|
|
|
|
2025-03-26 11:35:26 -07:00
|
|
|
|
sig { override.params(val: T.nilable(String), specs: T.anything).returns(T.nilable(String)) }
|
2018-08-02 10:29:40 +02:00
|
|
|
|
def url(val = nil, **specs)
|
2023-04-18 00:22:13 +01:00
|
|
|
|
return @url&.to_s if val.nil?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
|
2021-10-04 14:21:03 +01:00
|
|
|
|
specs = specs.dup
|
|
|
|
|
# Don't allow this to be set.
|
|
|
|
|
specs.delete(:insecure)
|
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
|
specs[:insecure] = true if @insecure
|
|
|
|
|
|
|
|
|
|
@url = URL.new(val, specs)
|
2021-04-15 18:06:54 +01:00
|
|
|
|
@downloader = nil
|
2023-04-18 00:22:13 +01:00
|
|
|
|
@download_strategy = @url.download_strategy
|
2025-03-26 11:35:26 -07:00
|
|
|
|
@url.to_s
|
2013-09-17 21:25:38 -05:00
|
|
|
|
end
|
|
|
|
|
|
2024-07-14 22:51:54 -04:00
|
|
|
|
sig { override.params(val: T.nilable(T.any(String, Version))).returns(T.nilable(Version)) }
|
2015-08-03 13:09:07 +01:00
|
|
|
|
def version(val = nil)
|
2023-04-18 00:22:13 +01:00
|
|
|
|
return super() if val.nil?
|
2022-09-01 18:25:26 +01:00
|
|
|
|
|
2023-09-01 19:37:32 +01:00
|
|
|
|
@version = case val
|
2023-05-01 07:59:36 +02:00
|
|
|
|
when String
|
|
|
|
|
val.blank? ? Version::NULL : Version.new(val)
|
|
|
|
|
when Version
|
|
|
|
|
val
|
2023-04-18 00:22:13 +01:00
|
|
|
|
end
|
2013-09-17 21:25:38 -05:00
|
|
|
|
end
|
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
|
def mirror(val)
|
2013-09-17 21:25:38 -05:00
|
|
|
|
mirrors << val
|
|
|
|
|
end
|
|
|
|
|
|
2018-01-21 08:29:38 -08:00
|
|
|
|
def patch(strip = :p1, src = nil, &block)
|
2024-07-14 11:42:22 -04:00
|
|
|
|
p = ::Patch.create(strip, src, &block)
|
2018-01-21 08:29:38 -08:00
|
|
|
|
patches << p
|
|
|
|
|
end
|
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
|
def using
|
|
|
|
|
@url&.using
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def specs
|
|
|
|
|
@url&.specs || {}.freeze
|
|
|
|
|
end
|
|
|
|
|
|
2018-07-14 18:13:23 +01:00
|
|
|
|
protected
|
|
|
|
|
|
2022-07-31 19:59:25 +01:00
|
|
|
|
def stage_resource(prefix, debug_symbols: false, &block)
|
2022-08-01 18:30:14 -07:00
|
|
|
|
Mktemp.new(prefix, retain_in_cache: debug_symbols).run(&block)
|
2018-07-14 18:13:23 +01:00
|
|
|
|
end
|
|
|
|
|
|
2013-09-17 21:25:38 -05:00
|
|
|
|
private
|
|
|
|
|
|
2022-09-16 01:50:44 +08:00
|
|
|
|
def determine_url_mirrors
|
|
|
|
|
extra_urls = []
|
2025-03-26 11:35:26 -07:00
|
|
|
|
url = T.must(self.url)
|
2022-09-16 01:50:44 +08:00
|
|
|
|
|
|
|
|
|
# glibc-bootstrap
|
|
|
|
|
if url.start_with?("https://github.com/Homebrew/glibc-bootstrap/releases/download")
|
2023-03-13 02:40:03 +01:00
|
|
|
|
if (artifact_domain = Homebrew::EnvConfig.artifact_domain.presence)
|
2024-05-14 16:03:35 +09:00
|
|
|
|
artifact_url = url.sub("https://github.com", artifact_domain)
|
|
|
|
|
return [artifact_url] if Homebrew::EnvConfig.artifact_domain_no_fallback?
|
|
|
|
|
|
|
|
|
|
extra_urls << artifact_url
|
2022-09-16 01:50:44 +08:00
|
|
|
|
end
|
2024-05-14 16:03:35 +09:00
|
|
|
|
|
2022-09-16 01:50:44 +08:00
|
|
|
|
if Homebrew::EnvConfig.bottle_domain != HOMEBREW_BOTTLE_DEFAULT_DOMAIN
|
|
|
|
|
tag, filename = url.split("/").last(2)
|
|
|
|
|
extra_urls << "#{Homebrew::EnvConfig.bottle_domain}/glibc-bootstrap/#{tag}/#{filename}"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-09-16 01:57:19 +08:00
|
|
|
|
# PyPI packages: PEP 503 – Simple Repository API <https://peps.python.org/pep-0503>
|
2023-03-13 02:38:03 +01:00
|
|
|
|
if (pip_index_url = Homebrew::EnvConfig.pip_index_url.presence)
|
|
|
|
|
pip_index_base_url = pip_index_url.chomp("/").chomp("/simple")
|
2022-09-16 01:57:19 +08:00
|
|
|
|
%w[https://files.pythonhosted.org https://pypi.org].each do |base_url|
|
|
|
|
|
extra_urls << url.sub(base_url, pip_index_base_url) if url.start_with?("#{base_url}/packages")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
|
[*extra_urls, *super].uniq
|
2022-09-16 01:50:44 +08:00
|
|
|
|
end
|
|
|
|
|
|
2024-08-14 21:59:04 +02:00
|
|
|
|
# A local resource that doesn't need to be downloaded.
|
|
|
|
|
class Local < Resource
|
|
|
|
|
def initialize(path)
|
|
|
|
|
super(File.basename(path))
|
2024-09-04 23:12:58 +02:00
|
|
|
|
@downloader = LocalBottleDownloadStrategy.new(path)
|
2024-08-14 21:59:04 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-07-14 11:42:22 -04:00
|
|
|
|
# A resource for a formula.
|
|
|
|
|
class Formula < Resource
|
|
|
|
|
sig { override.returns(String) }
|
|
|
|
|
def name
|
|
|
|
|
T.must(owner).name
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
sig { override.returns(String) }
|
|
|
|
|
def download_name
|
|
|
|
|
name
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-08-19 06:58:36 +02:00
|
|
|
|
# A resource containing a Go package.
|
2014-06-02 23:32:42 -07:00
|
|
|
|
class Go < Resource
|
2020-11-24 15:46:47 +01:00
|
|
|
|
def stage(target, &block)
|
|
|
|
|
super(target/name, &block)
|
2014-06-02 23:32:42 -07:00
|
|
|
|
end
|
|
|
|
|
end
|
2016-01-25 08:21:57 -08:00
|
|
|
|
|
2024-07-13 16:28:21 -04:00
|
|
|
|
# A resource for a bottle manifest.
|
|
|
|
|
class BottleManifest < Resource
|
2024-07-13 16:50:53 -04:00
|
|
|
|
class Error < RuntimeError; end
|
|
|
|
|
|
2024-07-13 16:28:21 -04:00
|
|
|
|
attr_reader :bottle
|
|
|
|
|
|
|
|
|
|
def initialize(bottle)
|
|
|
|
|
super("#{bottle.name}_bottle_manifest")
|
|
|
|
|
@bottle = bottle
|
2024-08-26 16:59:37 -04:00
|
|
|
|
@manifest_annotations = nil
|
2024-07-13 16:28:21 -04:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def verify_download_integrity(_filename)
|
2024-07-13 16:50:53 -04:00
|
|
|
|
# We don't have a checksum, but we can at least try parsing it.
|
|
|
|
|
tab
|
2024-07-13 16:28:21 -04:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def tab
|
2024-08-26 16:59:37 -04:00
|
|
|
|
tab = manifest_annotations["sh.brew.tab"]
|
|
|
|
|
raise Error, "Couldn't find tab from manifest." if tab.blank?
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
JSON.parse(tab)
|
|
|
|
|
rescue JSON::ParserError
|
|
|
|
|
raise Error, "Couldn't parse tab JSON."
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
sig { returns(T.nilable(Integer)) }
|
|
|
|
|
def bottle_size
|
|
|
|
|
manifest_annotations["sh.brew.bottle.size"]&.to_i
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
sig { returns(T.nilable(Integer)) }
|
|
|
|
|
def installed_size
|
|
|
|
|
manifest_annotations["sh.brew.bottle.installed_size"]&.to_i
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
|
|
def manifest_annotations
|
|
|
|
|
return @manifest_annotations unless @manifest_annotations.nil?
|
|
|
|
|
|
2024-07-13 16:28:21 -04:00
|
|
|
|
json = begin
|
|
|
|
|
JSON.parse(cached_download.read)
|
|
|
|
|
rescue JSON::ParserError
|
2024-07-13 16:50:53 -04:00
|
|
|
|
raise Error, "The downloaded GitHub Packages manifest was corrupted or modified (it is not valid JSON): " \
|
|
|
|
|
"\n#{cached_download}"
|
2024-07-13 16:28:21 -04:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
manifests = json["manifests"]
|
2024-07-13 16:50:53 -04:00
|
|
|
|
raise Error, "Missing 'manifests' section." if manifests.blank?
|
2024-07-13 16:28:21 -04:00
|
|
|
|
|
|
|
|
|
manifests_annotations = manifests.filter_map { |m| m["annotations"] }
|
2024-07-13 16:50:53 -04:00
|
|
|
|
raise Error, "Missing 'annotations' section." if manifests_annotations.blank?
|
2024-07-13 16:28:21 -04:00
|
|
|
|
|
|
|
|
|
bottle_digest = bottle.resource.checksum.hexdigest
|
|
|
|
|
image_ref = GitHubPackages.version_rebuild(bottle.resource.version, bottle.rebuild, bottle.tag.to_s)
|
|
|
|
|
manifest_annotations = manifests_annotations.find do |m|
|
|
|
|
|
next if m["sh.brew.bottle.digest"] != bottle_digest
|
|
|
|
|
|
|
|
|
|
m["org.opencontainers.image.ref.name"] == image_ref
|
|
|
|
|
end
|
2024-07-13 16:50:53 -04:00
|
|
|
|
raise Error, "Couldn't find manifest matching bottle checksum." if manifest_annotations.blank?
|
2024-07-13 16:28:21 -04:00
|
|
|
|
|
2024-08-26 16:59:37 -04:00
|
|
|
|
@manifest_annotations = manifest_annotations
|
2024-07-13 16:28:21 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-08-19 06:58:36 +02:00
|
|
|
|
# A resource containing a patch.
|
2024-07-14 11:42:22 -04:00
|
|
|
|
class Patch < Resource
|
2016-01-25 08:21:57 -08:00
|
|
|
|
attr_reader :patch_files
|
|
|
|
|
|
|
|
|
|
def initialize(&block)
|
|
|
|
|
@patch_files = []
|
2020-03-08 18:33:04 +00:00
|
|
|
|
@directory = nil
|
2016-01-25 08:21:57 -08:00
|
|
|
|
super "patch", &block
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def apply(*paths)
|
|
|
|
|
paths.flatten!
|
|
|
|
|
@patch_files.concat(paths)
|
|
|
|
|
@patch_files.uniq!
|
|
|
|
|
end
|
2020-03-08 18:33:04 +00:00
|
|
|
|
|
|
|
|
|
def directory(val = nil)
|
|
|
|
|
return @directory if val.nil?
|
|
|
|
|
|
|
|
|
|
@directory = val
|
|
|
|
|
end
|
2016-01-25 08:21:57 -08:00
|
|
|
|
end
|
2013-08-06 19:52:58 -07:00
|
|
|
|
end
|
2016-04-22 16:54:09 -04:00
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
|
# The context in which a {Resource#stage} occurs. Supports access to both
|
2018-10-18 21:42:43 -04:00
|
|
|
|
# the {Resource} and associated {Mktemp} in a single block argument. The interface
|
|
|
|
|
# is back-compatible with {Resource} itself as used in that context.
|
2016-04-22 16:54:09 -04:00
|
|
|
|
class ResourceStageContext
|
|
|
|
|
extend Forwardable
|
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
|
# The {Resource} that is being staged.
|
2016-04-22 16:54:09 -04:00
|
|
|
|
attr_reader :resource
|
2024-04-26 14:04:55 +02:00
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
|
# The {Mktemp} in which {#resource} is staged.
|
2016-04-22 16:54:09 -04:00
|
|
|
|
attr_reader :staging
|
|
|
|
|
|
|
|
|
|
def_delegators :@resource, :version, :url, :mirrors, :specs, :using, :source_modified_time
|
|
|
|
|
def_delegators :@staging, :retain!
|
|
|
|
|
|
|
|
|
|
def initialize(resource, staging)
|
|
|
|
|
@resource = resource
|
|
|
|
|
@staging = staging
|
|
|
|
|
end
|
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
|
sig { returns(String) }
|
2016-04-22 16:54:09 -04:00
|
|
|
|
def to_s
|
|
|
|
|
"<#{self.class}: resource=#{resource} staging=#{staging}>"
|
|
|
|
|
end
|
|
|
|
|
end
|