2023-12-12 10:10:18 -08:00
|
|
|
# typed: strict
|
2020-08-08 07:10:48 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-12-19 18:15:51 -05:00
|
|
|
require "livecheck/constants"
|
2020-12-19 20:36:41 +01:00
|
|
|
require "livecheck/error"
|
2021-01-22 12:25:13 -08:00
|
|
|
require "livecheck/livecheck_version"
|
2021-01-07 15:30:22 -05:00
|
|
|
require "livecheck/skip_conditions"
|
2020-08-27 22:46:06 +05:30
|
|
|
require "livecheck/strategy"
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
require "addressable"
|
2025-08-20 19:20:19 +01:00
|
|
|
require "utils/output"
|
2020-08-27 22:46:06 +05:30
|
|
|
|
2020-08-08 07:10:48 +05:30
|
|
|
module Homebrew
|
2020-11-05 17:17:03 -05:00
|
|
|
# The {Livecheck} module consists of methods used by the `brew livecheck`
|
|
|
|
# command. These methods print the requested livecheck information
|
2020-08-27 22:46:06 +05:30
|
|
|
# for formulae.
|
2020-08-08 07:10:48 +05:30
|
|
|
module Livecheck
|
2025-08-20 19:20:19 +01:00
|
|
|
extend Utils::Output::Mixin
|
|
|
|
|
2025-02-19 14:51:36 -05:00
|
|
|
NO_CURRENT_VERSION_MSG = "Unable to identify current version"
|
2025-02-19 15:06:00 -05:00
|
|
|
NO_VERSIONS_MSG = "Unable to get versions"
|
2025-02-19 14:51:36 -05:00
|
|
|
|
2023-12-12 10:10:18 -08:00
|
|
|
UNSTABLE_VERSION_KEYWORDS = T.let(%w[
|
2020-08-08 07:10:48 +05:30
|
|
|
alpha
|
|
|
|
beta
|
|
|
|
bpo
|
|
|
|
dev
|
|
|
|
experimental
|
|
|
|
prerelease
|
|
|
|
preview
|
|
|
|
rc
|
2023-12-12 10:10:18 -08:00
|
|
|
].freeze, T::Array[String])
|
2024-08-23 03:15:57 +01:00
|
|
|
private_constant :UNSTABLE_VERSION_KEYWORDS
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2025-02-22 21:51:41 -08:00
|
|
|
sig { params(strategy_class: T::Class[Strategic]).returns(String) }
|
2025-02-19 16:22:25 -05:00
|
|
|
private_class_method def self.livecheck_strategy_names(strategy_class)
|
2025-02-22 21:51:41 -08:00
|
|
|
@livecheck_strategy_names ||= T.let({}, T.nilable(T::Hash[T::Class[Strategic], String]))
|
2025-02-23 11:08:00 -08:00
|
|
|
@livecheck_strategy_names[strategy_class] ||= Utils.demodulize(strategy_class.name)
|
2020-12-14 14:30:36 +01:00
|
|
|
end
|
|
|
|
|
2025-02-22 21:51:41 -08:00
|
|
|
sig { params(strategy_class: T::Class[Strategic]).returns(T::Array[Symbol]) }
|
2025-02-15 16:52:19 -08:00
|
|
|
private_class_method def self.livecheck_find_versions_parameters(strategy_class)
|
2025-02-22 21:51:41 -08:00
|
|
|
@livecheck_find_versions_parameters ||= T.let({}, T.nilable(T::Hash[T::Class[Strategic], T::Array[Symbol]]))
|
2025-02-15 16:52:19 -08:00
|
|
|
@livecheck_find_versions_parameters[strategy_class] ||=
|
|
|
|
T::Utils.signature_for_method(strategy_class.method(:find_versions)).parameters.map(&:second)
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
end
|
|
|
|
|
2021-01-24 19:07:17 +05:30
|
|
|
# Uses `formulae_and_casks_to_check` to identify taps in use other than
|
|
|
|
# homebrew/core and homebrew/cask and loads strategies from them.
|
2021-03-04 01:01:56 +05:30
|
|
|
sig { params(formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)]).void }
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.load_other_tap_strategies(formulae_and_casks_to_check)
|
2021-01-11 08:29:34 +05:30
|
|
|
other_taps = {}
|
|
|
|
formulae_and_casks_to_check.each do |formula_or_cask|
|
|
|
|
next if formula_or_cask.tap.blank?
|
2023-12-13 13:17:12 +00:00
|
|
|
next if formula_or_cask.tap.core_tap?
|
|
|
|
next if formula_or_cask.tap.core_cask_tap?
|
2021-01-11 08:29:34 +05:30
|
|
|
next if other_taps[formula_or_cask.tap.name]
|
|
|
|
|
|
|
|
other_taps[formula_or_cask.tap.name] = formula_or_cask.tap
|
|
|
|
end
|
|
|
|
other_taps = other_taps.sort.to_h
|
|
|
|
|
|
|
|
other_taps.each_value do |tap|
|
|
|
|
tap_strategy_path = "#{tap.path}/livecheck/strategy"
|
2024-02-22 23:21:28 +00:00
|
|
|
Dir["#{tap_strategy_path}/*.rb"].each { require(_1) } if Dir.exist?(tap_strategy_path)
|
2021-01-11 08:29:34 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-07-19 11:21:29 -04:00
|
|
|
# Resolve formula/cask references in `livecheck` blocks to a final formula
|
|
|
|
# or cask.
|
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
formula_or_cask: T.any(Formula, Cask::Cask),
|
|
|
|
first_formula_or_cask: T.any(Formula, Cask::Cask),
|
|
|
|
references: T::Array[T.any(Formula, Cask::Cask)],
|
|
|
|
full_name: T::Boolean,
|
|
|
|
debug: T::Boolean,
|
|
|
|
).returns(T.nilable(T::Array[T.untyped]))
|
|
|
|
}
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.resolve_livecheck_reference(
|
2021-07-19 11:21:29 -04:00
|
|
|
formula_or_cask,
|
|
|
|
first_formula_or_cask = formula_or_cask,
|
|
|
|
references = [],
|
|
|
|
full_name: false,
|
|
|
|
debug: false
|
|
|
|
)
|
2024-12-02 10:06:14 -05:00
|
|
|
# Check the `livecheck` block for a formula or cask reference
|
2021-07-19 11:21:29 -04:00
|
|
|
livecheck = formula_or_cask.livecheck
|
|
|
|
livecheck_formula = livecheck.formula
|
|
|
|
livecheck_cask = livecheck.cask
|
|
|
|
return [nil, references] if livecheck_formula.blank? && livecheck_cask.blank?
|
|
|
|
|
|
|
|
# Load the referenced formula or cask
|
2023-07-10 14:50:53 +01:00
|
|
|
referenced_formula_or_cask = Homebrew.with_no_api_env do
|
|
|
|
if livecheck_formula
|
|
|
|
Formulary.factory(livecheck_formula)
|
|
|
|
elsif livecheck_cask
|
|
|
|
Cask::CaskLoader.load(livecheck_cask)
|
|
|
|
end
|
2021-07-19 11:21:29 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Error if a `livecheck` block references a formula/cask that was already
|
|
|
|
# referenced (or itself)
|
|
|
|
if referenced_formula_or_cask == first_formula_or_cask ||
|
|
|
|
referenced_formula_or_cask == formula_or_cask ||
|
|
|
|
references.include?(referenced_formula_or_cask)
|
|
|
|
if debug
|
|
|
|
# Print the chain of references for debugging
|
|
|
|
puts "Reference Chain:"
|
2024-03-07 16:20:20 +00:00
|
|
|
puts package_or_resource_name(first_formula_or_cask, full_name:)
|
2021-07-19 11:21:29 -04:00
|
|
|
|
|
|
|
references << referenced_formula_or_cask
|
|
|
|
references.each do |ref_formula_or_cask|
|
2024-03-07 16:20:20 +00:00
|
|
|
puts package_or_resource_name(ref_formula_or_cask, full_name:)
|
2021-07-19 11:21:29 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
raise "Circular formula/cask reference encountered"
|
|
|
|
end
|
|
|
|
references << referenced_formula_or_cask
|
|
|
|
|
|
|
|
# Check the referenced formula/cask for a reference
|
|
|
|
next_referenced_formula_or_cask, next_references = resolve_livecheck_reference(
|
|
|
|
referenced_formula_or_cask,
|
|
|
|
first_formula_or_cask,
|
|
|
|
references,
|
2024-03-07 16:20:20 +00:00
|
|
|
full_name:,
|
|
|
|
debug:,
|
2021-07-19 11:21:29 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
# Returning references along with the final referenced formula/cask
|
|
|
|
# allows us to print the chain of references in the debug output
|
|
|
|
[
|
|
|
|
next_referenced_formula_or_cask || referenced_formula_or_cask,
|
|
|
|
next_references,
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
2020-09-02 12:24:21 -07:00
|
|
|
# Executes the livecheck logic for each formula/cask in the
|
|
|
|
# `formulae_and_casks_to_check` array and prints the results.
|
2021-01-17 22:45:55 -08:00
|
|
|
sig {
|
2021-01-04 13:41:19 -08:00
|
|
|
params(
|
2022-07-27 20:43:07 +02:00
|
|
|
formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)],
|
|
|
|
full_name: T::Boolean,
|
|
|
|
handle_name_conflict: T::Boolean,
|
|
|
|
check_resources: T::Boolean,
|
|
|
|
json: T::Boolean,
|
|
|
|
newer_only: T::Boolean,
|
2024-03-21 11:47:37 +00:00
|
|
|
extract_plist: T::Boolean,
|
2022-07-27 20:43:07 +02:00
|
|
|
debug: T::Boolean,
|
|
|
|
quiet: T::Boolean,
|
|
|
|
verbose: T::Boolean,
|
2021-01-04 13:41:19 -08:00
|
|
|
).void
|
2021-01-17 22:45:55 -08:00
|
|
|
}
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.run_checks(
|
2020-12-14 14:30:36 +01:00
|
|
|
formulae_and_casks_to_check,
|
2022-07-27 13:54:20 +02:00
|
|
|
full_name: false, handle_name_conflict: false, check_resources: false, json: false, newer_only: false,
|
2024-03-21 11:47:37 +00:00
|
|
|
extract_plist: false, debug: false, quiet: false, verbose: false
|
2020-12-14 14:30:36 +01:00
|
|
|
)
|
2021-01-11 08:29:34 +05:30
|
|
|
load_other_tap_strategies(formulae_and_casks_to_check)
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2021-03-04 01:01:56 +05:30
|
|
|
ambiguous_casks = []
|
|
|
|
if handle_name_conflict
|
2023-04-04 15:37:24 +01:00
|
|
|
ambiguous_casks = formulae_and_casks_to_check
|
2022-09-14 04:54:52 +02:00
|
|
|
.group_by { |item| package_or_resource_name(item, full_name: true) }
|
|
|
|
.values
|
|
|
|
.select { |items| items.length > 1 }
|
|
|
|
.flatten
|
|
|
|
.select { |item| item.is_a?(Cask::Cask) }
|
2021-03-04 01:01:56 +05:30
|
|
|
end
|
|
|
|
|
2021-03-04 01:39:37 +05:30
|
|
|
ambiguous_names = []
|
|
|
|
unless full_name
|
2021-03-04 23:54:25 +05:30
|
|
|
ambiguous_names =
|
2022-09-14 04:54:52 +02:00
|
|
|
(formulae_and_casks_to_check - ambiguous_casks).group_by { |item| package_or_resource_name(item) }
|
2021-03-04 23:54:25 +05:30
|
|
|
.values
|
|
|
|
.select { |items| items.length > 1 }
|
|
|
|
.flatten
|
2021-03-04 01:39:37 +05:30
|
|
|
end
|
|
|
|
|
2021-01-04 13:41:19 -08:00
|
|
|
has_a_newer_upstream_version = T.let(false, T::Boolean)
|
2020-09-03 00:41:16 +05:30
|
|
|
|
2024-03-21 11:47:37 +00:00
|
|
|
formulae_and_casks_total = formulae_and_casks_to_check.count
|
|
|
|
if json && !quiet && $stderr.tty?
|
2020-09-18 02:39:52 +05:30
|
|
|
Tty.with($stderr) do |stderr|
|
|
|
|
stderr.puts Formatter.headline("Running checks", color: :blue)
|
|
|
|
end
|
|
|
|
|
2023-09-04 21:54:30 +01:00
|
|
|
require "ruby-progressbar"
|
2020-09-03 00:41:16 +05:30
|
|
|
progress = ProgressBar.create(
|
2020-12-12 10:29:25 -05:00
|
|
|
total: formulae_and_casks_total,
|
2020-09-03 00:41:16 +05:30
|
|
|
progress_mark: "#",
|
|
|
|
remainder_mark: ".",
|
|
|
|
format: " %t: [%B] %c/%C ",
|
|
|
|
output: $stderr,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2024-03-29 09:25:36 -04:00
|
|
|
# Allow ExtractPlist strategy if only one formula/cask is being checked.
|
2024-03-21 11:47:37 +00:00
|
|
|
extract_plist = true if formulae_and_casks_total == 1
|
|
|
|
|
2020-09-03 20:33:24 -07:00
|
|
|
formulae_checked = formulae_and_casks_to_check.map.with_index do |formula_or_cask, i|
|
2024-11-02 15:03:10 -07:00
|
|
|
case formula_or_cask
|
|
|
|
when Formula
|
|
|
|
formula = formula_or_cask
|
|
|
|
formula.head&.downloader&.quiet!
|
|
|
|
when Cask::Cask
|
|
|
|
cask = formula_or_cask
|
|
|
|
end
|
2021-03-04 01:39:37 +05:30
|
|
|
|
|
|
|
use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
|
2022-09-14 04:54:52 +02:00
|
|
|
name = package_or_resource_name(formula_or_cask, full_name: use_full_name)
|
2020-09-02 12:24:21 -07:00
|
|
|
|
2021-07-19 11:21:29 -04:00
|
|
|
referenced_formula_or_cask, livecheck_references =
|
2024-03-07 16:20:20 +00:00
|
|
|
resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug:)
|
2021-07-19 11:21:29 -04:00
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
if debug && i.positive?
|
2020-08-08 07:10:48 +05:30
|
|
|
puts <<~EOS
|
|
|
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
EOS
|
2021-02-18 15:05:01 +05:30
|
|
|
elsif debug
|
|
|
|
puts
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
2021-07-19 11:21:29 -04:00
|
|
|
# Check skip conditions for a referenced formula/cask
|
|
|
|
if referenced_formula_or_cask
|
|
|
|
skip_info = SkipConditions.referenced_skip_information(
|
|
|
|
referenced_formula_or_cask,
|
|
|
|
name,
|
2024-03-29 09:22:08 -04:00
|
|
|
full_name: use_full_name,
|
2024-03-07 16:20:20 +00:00
|
|
|
verbose:,
|
2024-03-29 09:22:08 -04:00
|
|
|
extract_plist:,
|
2021-07-19 11:21:29 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2024-03-29 09:22:08 -04:00
|
|
|
skip_info ||= SkipConditions.skip_information(
|
|
|
|
formula_or_cask,
|
|
|
|
full_name: use_full_name,
|
|
|
|
verbose:,
|
|
|
|
extract_plist:,
|
|
|
|
)
|
2021-01-07 15:30:22 -05:00
|
|
|
if skip_info.present?
|
2022-06-08 15:49:38 -04:00
|
|
|
next skip_info if json && !newer_only
|
2021-01-07 15:30:22 -05:00
|
|
|
|
2022-06-08 15:14:03 -04:00
|
|
|
SkipConditions.print_skip_information(skip_info) if !newer_only && !quiet
|
2021-01-07 15:30:22 -05:00
|
|
|
next
|
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2020-09-09 13:27:12 +05:30
|
|
|
# Use the `stable` version for comparison except for installed
|
2025-08-15 22:33:23 -04:00
|
|
|
# HEAD-only formulae. A formula with `stable` and `head` that's
|
2020-09-09 13:27:12 +05:30
|
|
|
# installed using `--head` will still use the `stable` version for
|
|
|
|
# comparison.
|
2020-12-11 18:58:01 +01:00
|
|
|
current = if formula
|
2020-12-11 16:24:49 +01:00
|
|
|
if formula.head_only?
|
2025-02-19 14:51:36 -05:00
|
|
|
formula_commit = formula.any_installed_version&.version&.commit
|
|
|
|
Version.new(formula_commit) if formula_commit
|
|
|
|
elsif (stable = formula.stable)
|
|
|
|
stable.version
|
2020-12-11 16:24:49 +01:00
|
|
|
end
|
|
|
|
else
|
|
|
|
Version.new(formula_or_cask.version)
|
2020-08-31 09:59:02 -07:00
|
|
|
end
|
2025-02-19 14:51:36 -05:00
|
|
|
unless current
|
|
|
|
raise Livecheck::Error, NO_CURRENT_VERSION_MSG unless json
|
|
|
|
next if quiet
|
|
|
|
|
|
|
|
next status_hash(formula_or_cask, "error", [NO_CURRENT_VERSION_MSG], full_name: use_full_name, verbose:)
|
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2021-01-17 11:24:52 -08:00
|
|
|
current_str = current.to_s
|
2022-08-17 17:41:34 +02:00
|
|
|
current = LivecheckVersion.create(formula_or_cask, current)
|
2021-01-17 11:24:52 -08:00
|
|
|
|
2020-12-12 10:30:20 -05:00
|
|
|
latest = if formula&.head_only?
|
2024-07-25 10:21:42 -04:00
|
|
|
Version.new(T.must(formula.head).downloader.fetch_last_commit)
|
2020-12-12 10:30:20 -05:00
|
|
|
else
|
2022-07-27 13:54:20 +02:00
|
|
|
version_info = latest_version(
|
|
|
|
formula_or_cask,
|
2024-03-07 16:20:20 +00:00
|
|
|
referenced_formula_or_cask:,
|
|
|
|
livecheck_references:,
|
|
|
|
json:, full_name: use_full_name, verbose:, debug:
|
2022-07-27 13:54:20 +02:00
|
|
|
)
|
|
|
|
version_info[:latest] if version_info.present?
|
2022-07-27 15:13:55 +02:00
|
|
|
end
|
|
|
|
|
2022-09-25 20:48:44 +02:00
|
|
|
check_for_resources = check_resources && formula_or_cask.is_a?(Formula) && formula_or_cask.resources.present?
|
|
|
|
if check_for_resources
|
|
|
|
resource_version_info = formula_or_cask.resources.map do |resource|
|
2024-03-07 16:20:20 +00:00
|
|
|
res_skip_info ||= SkipConditions.skip_information(resource, verbose:)
|
2022-09-25 20:48:44 +02:00
|
|
|
if res_skip_info.present?
|
|
|
|
res_skip_info
|
|
|
|
else
|
|
|
|
res_version_info = resource_version(
|
|
|
|
resource,
|
2022-12-18 18:11:51 -05:00
|
|
|
latest.to_s,
|
2024-03-07 16:20:20 +00:00
|
|
|
json:,
|
2025-01-07 01:46:24 +05:30
|
|
|
full_name: use_full_name,
|
2024-03-07 16:20:20 +00:00
|
|
|
debug:,
|
|
|
|
quiet:,
|
|
|
|
verbose:,
|
2022-09-25 20:48:44 +02:00
|
|
|
)
|
|
|
|
if res_version_info.empty?
|
2025-02-19 15:06:00 -05:00
|
|
|
status_hash(resource, "error", [NO_VERSIONS_MSG], verbose:)
|
2022-09-25 20:48:44 +02:00
|
|
|
else
|
|
|
|
res_version_info
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end.compact_blank
|
2022-09-26 19:37:46 +02:00
|
|
|
Homebrew.failed = true if resource_version_info.any? { |info| info[:status] == "error" }
|
2022-09-25 20:48:44 +02:00
|
|
|
end
|
|
|
|
|
2020-08-08 07:10:48 +05:30
|
|
|
if latest.blank?
|
2025-02-19 15:06:00 -05:00
|
|
|
raise Livecheck::Error, NO_VERSIONS_MSG unless json
|
2022-06-08 15:49:38 -04:00
|
|
|
next if quiet
|
2020-08-08 07:10:48 +05:30
|
|
|
|
|
|
|
next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages]
|
|
|
|
|
2025-02-19 15:06:00 -05:00
|
|
|
latest_info = status_hash(formula_or_cask, "error", [NO_VERSIONS_MSG], full_name: use_full_name,
|
2024-03-07 16:20:20 +00:00
|
|
|
verbose:)
|
2022-09-18 17:29:44 +02:00
|
|
|
if check_for_resources
|
2023-12-12 10:09:49 -08:00
|
|
|
unless verbose
|
2023-12-12 10:19:58 -08:00
|
|
|
resource_version_info.map! do |info|
|
|
|
|
info.delete(:meta)
|
|
|
|
info
|
2023-12-12 10:09:49 -08:00
|
|
|
end
|
|
|
|
end
|
2022-09-18 17:29:44 +02:00
|
|
|
latest_info[:resources] = resource_version_info
|
|
|
|
end
|
2022-09-14 06:05:43 +02:00
|
|
|
|
|
|
|
next latest_info
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/)
|
|
|
|
latest = Version.new(m[1])
|
|
|
|
end
|
|
|
|
|
2021-01-17 11:24:52 -08:00
|
|
|
latest_str = latest.to_s
|
2022-08-17 17:41:34 +02:00
|
|
|
latest = LivecheckVersion.create(formula_or_cask, latest)
|
2021-01-17 11:24:52 -08:00
|
|
|
|
2020-09-02 12:24:21 -07:00
|
|
|
is_outdated = if formula&.head_only?
|
2020-08-29 00:32:34 +05:30
|
|
|
# A HEAD-only formula is considered outdated if the latest upstream
|
|
|
|
# commit hash is different than the installed version's commit hash
|
2020-08-08 07:10:48 +05:30
|
|
|
(current != latest)
|
|
|
|
else
|
|
|
|
(current < latest)
|
|
|
|
end
|
|
|
|
|
2020-09-02 12:24:21 -07:00
|
|
|
is_newer_than_upstream = (formula&.stable? || cask) && (current > latest)
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2020-12-12 11:00:02 -05:00
|
|
|
info = {}
|
2021-01-07 15:30:22 -05:00
|
|
|
info[:formula] = name if formula
|
|
|
|
info[:cask] = name if cask
|
2020-12-12 11:00:02 -05:00
|
|
|
info[:version] = {
|
2021-01-17 11:24:52 -08:00
|
|
|
current: current_str,
|
|
|
|
latest: latest_str,
|
2024-03-20 22:50:14 -04:00
|
|
|
latest_throttled: version_info&.dig(:latest_throttled),
|
2020-12-12 11:00:02 -05:00
|
|
|
outdated: is_outdated,
|
|
|
|
newer_than_upstream: is_newer_than_upstream,
|
2024-03-20 22:50:14 -04:00
|
|
|
}.compact
|
2020-12-12 11:00:02 -05:00
|
|
|
info[:meta] = {
|
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: formula_or_cask.livecheck_defined?,
|
2020-12-12 11:00:02 -05:00
|
|
|
}
|
2020-09-02 12:24:21 -07:00
|
|
|
info[:meta][:head_only] = true if formula&.head_only?
|
2020-08-08 07:10:48 +05:30
|
|
|
info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta)
|
|
|
|
|
2022-08-11 21:00:28 +02:00
|
|
|
info[:resources] = resource_version_info if check_for_resources
|
2022-08-03 16:07:48 +02:00
|
|
|
|
|
|
|
next if newer_only && !info[:version][:outdated]
|
|
|
|
|
|
|
|
has_a_newer_upstream_version ||= true
|
|
|
|
|
|
|
|
if json
|
|
|
|
progress&.increment
|
2023-12-12 10:09:49 -08:00
|
|
|
info.delete(:meta) unless verbose
|
|
|
|
if check_for_resources && !verbose
|
2025-03-26 11:00:11 -07:00
|
|
|
resource_version_info.map! do |resource_info|
|
|
|
|
resource_info.delete(:meta)
|
|
|
|
resource_info
|
2023-12-12 10:09:49 -08:00
|
|
|
end
|
|
|
|
end
|
2022-08-03 16:07:48 +02:00
|
|
|
next info
|
|
|
|
end
|
|
|
|
puts if debug
|
2024-03-07 16:20:20 +00:00
|
|
|
print_latest_version(info, verbose:, ambiguous_cask: ambiguous_casks.include?(formula_or_cask))
|
|
|
|
print_resources_info(resource_version_info, verbose:) if check_for_resources
|
2020-08-08 07:10:48 +05:30
|
|
|
nil
|
|
|
|
rescue => e
|
|
|
|
Homebrew.failed = true
|
2021-03-04 01:39:37 +05:30
|
|
|
use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
if json
|
2020-09-03 00:41:16 +05:30
|
|
|
progress&.increment
|
2023-02-21 00:25:02 +00:00
|
|
|
unless quiet
|
|
|
|
status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name,
|
2024-03-07 16:20:20 +00:00
|
|
|
verbose:)
|
2023-02-21 00:25:02 +00:00
|
|
|
end
|
2020-12-14 14:30:36 +01:00
|
|
|
elsif !quiet
|
2022-09-14 04:54:52 +02:00
|
|
|
name = package_or_resource_name(formula_or_cask, full_name: use_full_name)
|
2021-03-04 01:01:56 +05:30
|
|
|
name += " (cask)" if ambiguous_casks.include?(formula_or_cask)
|
2021-02-27 22:39:12 +05:30
|
|
|
|
|
|
|
onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}"
|
2024-07-15 13:44:01 -04:00
|
|
|
if debug && !e.is_a?(Livecheck::Error)
|
|
|
|
require "utils/backtrace"
|
|
|
|
$stderr.puts Utils::Backtrace.clean(e)
|
|
|
|
end
|
2024-03-07 16:20:20 +00:00
|
|
|
print_resources_info(resource_version_info, verbose:) if check_for_resources
|
2020-08-08 07:10:48 +05:30
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-08-15 17:43:36 -07:00
|
|
|
puts "No newer upstream versions." if newer_only && !has_a_newer_upstream_version && !debug && !json && !quiet
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
return unless json
|
2020-09-03 00:41:16 +05:30
|
|
|
|
|
|
|
if progress
|
|
|
|
progress.finish
|
2020-09-18 02:39:52 +05:30
|
|
|
Tty.with($stderr) do |stderr|
|
|
|
|
stderr.print "#{Tty.up}#{Tty.erase_line}" * 2
|
|
|
|
end
|
2020-09-03 00:41:16 +05:30
|
|
|
end
|
|
|
|
|
2021-04-09 14:06:21 +01:00
|
|
|
puts JSON.pretty_generate(formulae_checked.compact)
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
2022-09-14 04:54:52 +02:00
|
|
|
sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource), full_name: T::Boolean).returns(String) }
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.package_or_resource_name(package_or_resource, full_name: false)
|
2022-09-14 04:54:52 +02:00
|
|
|
case package_or_resource
|
2020-12-12 11:36:43 -05:00
|
|
|
when Formula
|
2024-03-07 16:20:20 +00:00
|
|
|
formula_name(package_or_resource, full_name:)
|
2020-12-12 11:36:43 -05:00
|
|
|
when Cask::Cask
|
2024-03-07 16:20:20 +00:00
|
|
|
cask_name(package_or_resource, full_name:)
|
2022-09-14 04:54:52 +02:00
|
|
|
when Resource
|
|
|
|
package_or_resource.name
|
2021-01-17 11:24:52 -08:00
|
|
|
else
|
2022-09-14 04:54:52 +02:00
|
|
|
T.absurd(package_or_resource)
|
2020-09-02 12:24:21 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
# Returns the fully-qualified name of a cask if the `full_name` argument is
|
|
|
|
# provided; returns the name otherwise.
|
|
|
|
sig { params(cask: Cask::Cask, full_name: T::Boolean).returns(String) }
|
2024-08-23 03:15:57 +01:00
|
|
|
private_class_method def self.cask_name(cask, full_name: false)
|
2020-12-14 14:30:36 +01:00
|
|
|
full_name ? cask.full_name : cask.token
|
2020-09-02 12:24:21 -07:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Returns the fully-qualified name of a formula if the `full_name` argument is
|
|
|
|
# provided; returns the name otherwise.
|
2020-12-14 14:30:36 +01:00
|
|
|
sig { params(formula: Formula, full_name: T::Boolean).returns(String) }
|
2024-08-23 03:15:57 +01:00
|
|
|
private_class_method def self.formula_name(formula, full_name: false)
|
2020-12-14 14:30:36 +01:00
|
|
|
full_name ? formula.full_name : formula.name
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
2021-01-17 22:45:55 -08:00
|
|
|
sig {
|
2021-01-04 13:41:19 -08:00
|
|
|
params(
|
2022-07-27 18:25:12 +02:00
|
|
|
package_or_resource: T.any(Formula, Cask::Cask, Resource),
|
2022-07-27 20:43:07 +02:00
|
|
|
status_str: String,
|
|
|
|
messages: T.nilable(T::Array[String]),
|
|
|
|
full_name: T::Boolean,
|
|
|
|
verbose: T::Boolean,
|
2023-12-12 10:10:18 -08:00
|
|
|
).returns(T::Hash[Symbol, T.untyped])
|
2021-01-17 22:45:55 -08:00
|
|
|
}
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.status_hash(package_or_resource, status_str, messages = nil, full_name: false, verbose: false)
|
2022-07-27 18:25:12 +02:00
|
|
|
formula = package_or_resource if package_or_resource.is_a?(Formula)
|
|
|
|
cask = package_or_resource if package_or_resource.is_a?(Cask::Cask)
|
|
|
|
resource = package_or_resource if package_or_resource.is_a?(Resource)
|
2020-09-02 12:24:21 -07:00
|
|
|
|
2020-12-12 11:00:02 -05:00
|
|
|
status_hash = {}
|
2020-09-02 12:24:21 -07:00
|
|
|
if formula
|
2024-03-07 16:20:20 +00:00
|
|
|
status_hash[:formula] = formula_name(formula, full_name:)
|
2020-12-12 11:36:43 -05:00
|
|
|
elsif cask
|
2024-03-07 16:20:20 +00:00
|
|
|
status_hash[:cask] = cask_name(cask, full_name:)
|
2022-07-27 18:25:12 +02:00
|
|
|
elsif resource
|
2022-08-11 21:50:54 +02:00
|
|
|
status_hash[:resource] = resource.name
|
2020-09-02 12:24:21 -07:00
|
|
|
end
|
2020-12-12 11:00:02 -05:00
|
|
|
status_hash[:status] = status_str
|
|
|
|
status_hash[:messages] = messages if messages.is_a?(Array)
|
2020-09-02 12:24:21 -07:00
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
status_hash[:meta] = {
|
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: package_or_resource.livecheck_defined?,
|
2020-12-14 14:30:36 +01:00
|
|
|
}
|
|
|
|
status_hash[:meta][:head_only] = true if formula&.head_only?
|
2020-08-08 07:10:48 +05:30
|
|
|
|
|
|
|
status_hash
|
|
|
|
end
|
|
|
|
|
2022-07-31 10:08:39 +02:00
|
|
|
# Formats and prints the livecheck result for a formula/cask/resource.
|
2023-12-12 10:10:18 -08:00
|
|
|
sig { params(info: T::Hash[Symbol, T.untyped], verbose: T::Boolean, ambiguous_cask: T::Boolean).void }
|
2024-08-23 03:15:57 +01:00
|
|
|
private_class_method def self.print_latest_version(info, verbose: false, ambiguous_cask: false)
|
2022-09-27 00:36:33 -04:00
|
|
|
package_or_resource_s = info[:resource].present? ? " " : ""
|
2022-07-31 10:08:39 +02:00
|
|
|
package_or_resource_s += "#{Tty.blue}#{info[:formula] || info[:cask] || info[:resource]}#{Tty.reset}"
|
2022-08-03 18:41:44 +05:00
|
|
|
package_or_resource_s += " (cask)" if ambiguous_cask
|
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
|
|
|
package_or_resource_s += " (guessed)" if verbose && !info[:meta][:livecheck_defined]
|
2020-08-08 07:10:48 +05:30
|
|
|
|
|
|
|
current_s = if info[:version][:newer_than_upstream]
|
|
|
|
"#{Tty.red}#{info[:version][:current]}#{Tty.reset}"
|
|
|
|
else
|
|
|
|
info[:version][:current]
|
|
|
|
end
|
|
|
|
|
|
|
|
latest_s = if info[:version][:outdated]
|
|
|
|
"#{Tty.green}#{info[:version][:latest]}#{Tty.reset}"
|
|
|
|
else
|
|
|
|
info[:version][:latest]
|
|
|
|
end
|
|
|
|
|
2022-07-31 10:08:39 +02:00
|
|
|
puts "#{package_or_resource_s}: #{current_s} ==> #{latest_s}"
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
2022-09-27 00:59:37 -07:00
|
|
|
# Prints the livecheck result for the resources of a given Formula.
|
2023-12-12 10:10:18 -08:00
|
|
|
sig { params(info: T::Array[T::Hash[Symbol, T.untyped]], verbose: T::Boolean).void }
|
2024-08-23 03:15:57 +01:00
|
|
|
private_class_method def self.print_resources_info(info, verbose: false)
|
2022-09-14 04:54:52 +02:00
|
|
|
info.each do |r_info|
|
2022-09-18 21:27:10 +02:00
|
|
|
if r_info[:status] && r_info[:messages]
|
2022-09-14 04:54:52 +02:00
|
|
|
SkipConditions.print_skip_information(r_info)
|
|
|
|
else
|
2024-03-07 16:20:20 +00:00
|
|
|
print_latest_version(r_info, verbose:)
|
2022-09-14 04:54:52 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-01-17 22:45:55 -08:00
|
|
|
sig {
|
2021-01-12 15:00:49 -05:00
|
|
|
params(
|
2022-07-27 20:43:07 +02:00
|
|
|
livecheck_url: T.any(String, Symbol),
|
2022-07-24 15:47:40 +02:00
|
|
|
package_or_resource: T.any(Formula, Cask::Cask, Resource),
|
2024-10-24 09:00:18 -04:00
|
|
|
).returns(String)
|
2021-01-17 22:45:55 -08:00
|
|
|
}
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.livecheck_url_to_string(livecheck_url, package_or_resource)
|
2024-10-24 09:00:18 -04:00
|
|
|
livecheck_url_string = case livecheck_url
|
2021-01-12 15:00:49 -05:00
|
|
|
when String
|
|
|
|
livecheck_url
|
|
|
|
when :url
|
2022-07-24 17:39:07 +02:00
|
|
|
package_or_resource.url&.to_s if package_or_resource.is_a?(Cask::Cask) || package_or_resource.is_a?(Resource)
|
2021-01-12 15:00:49 -05:00
|
|
|
when :head, :stable
|
2022-07-27 13:27:21 +02:00
|
|
|
package_or_resource.send(livecheck_url)&.url if package_or_resource.is_a?(Formula)
|
2021-01-12 15:00:49 -05:00
|
|
|
when :homepage
|
2022-08-07 19:36:06 +02:00
|
|
|
package_or_resource.homepage unless package_or_resource.is_a?(Resource)
|
2021-01-12 15:00:49 -05:00
|
|
|
end
|
2024-10-24 09:00:18 -04:00
|
|
|
|
|
|
|
if livecheck_url.is_a?(Symbol) && !livecheck_url_string
|
|
|
|
raise ArgumentError, "`url #{livecheck_url.inspect}` does not reference a checkable URL"
|
|
|
|
end
|
|
|
|
|
|
|
|
livecheck_url_string
|
2021-01-12 15:00:49 -05:00
|
|
|
end
|
|
|
|
|
2022-09-27 00:18:20 -04:00
|
|
|
# Returns an Array containing the formula/cask/resource URLs that can be used by livecheck.
|
2022-07-24 15:47:40 +02:00
|
|
|
sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource)).returns(T::Array[String]) }
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.checkable_urls(package_or_resource)
|
2020-08-08 07:10:48 +05:30
|
|
|
urls = []
|
|
|
|
|
2022-07-24 15:47:40 +02:00
|
|
|
case package_or_resource
|
2020-09-03 20:43:21 -07:00
|
|
|
when Formula
|
2022-07-24 15:47:40 +02:00
|
|
|
if package_or_resource.stable
|
2023-07-24 14:01:53 -07:00
|
|
|
urls << T.must(package_or_resource.stable).url
|
|
|
|
urls.concat(T.must(package_or_resource.stable).mirrors)
|
2020-09-03 20:43:21 -07:00
|
|
|
end
|
2023-07-24 14:01:53 -07:00
|
|
|
urls << T.must(package_or_resource.head).url if package_or_resource.head
|
2022-07-24 15:47:40 +02:00
|
|
|
urls << package_or_resource.homepage if package_or_resource.homepage
|
2020-09-03 20:43:21 -07:00
|
|
|
when Cask::Cask
|
2022-07-24 15:47:40 +02:00
|
|
|
urls << package_or_resource.url.to_s if package_or_resource.url
|
|
|
|
urls << package_or_resource.homepage if package_or_resource.homepage
|
2022-09-25 00:53:44 +02:00
|
|
|
when Resource
|
|
|
|
urls << package_or_resource.url
|
2021-01-17 11:24:52 -08:00
|
|
|
else
|
2022-07-24 15:47:40 +02:00
|
|
|
T.absurd(package_or_resource)
|
2020-09-03 20:43:21 -07:00
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2021-08-13 16:29:06 -04:00
|
|
|
urls.compact.uniq
|
2020-09-02 12:24:21 -07:00
|
|
|
end
|
|
|
|
|
2022-09-18 21:27:10 +02:00
|
|
|
# livecheck should fetch a URL using brewed curl if the formula/cask
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
# contains a `stable`/`url` or `head` URL `using: :homebrew_curl` that
|
|
|
|
# shares the same root domain.
|
2022-09-18 21:27:10 +02:00
|
|
|
sig { params(formula_or_cask: T.any(Formula, Cask::Cask), url: String).returns(T::Boolean) }
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.use_homebrew_curl?(formula_or_cask, url)
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
url_root_domain = Addressable::URI.parse(url)&.domain
|
|
|
|
return false if url_root_domain.blank?
|
2021-11-23 23:22:41 -05:00
|
|
|
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
# Collect root domains of URLs with `using: :homebrew_curl`
|
|
|
|
homebrew_curl_root_domains = []
|
2022-09-18 21:27:10 +02:00
|
|
|
case formula_or_cask
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
when Formula
|
|
|
|
[:stable, :head].each do |spec_name|
|
2022-09-18 21:27:10 +02:00
|
|
|
next unless (spec = formula_or_cask.send(spec_name))
|
2023-04-18 15:06:50 -07:00
|
|
|
next if spec.using != :homebrew_curl
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
|
|
|
|
domain = Addressable::URI.parse(spec.url)&.domain
|
|
|
|
homebrew_curl_root_domains << domain if domain.present?
|
2021-11-23 23:22:41 -05:00
|
|
|
end
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
when Cask::Cask
|
2024-08-23 16:39:23 +01:00
|
|
|
return false if formula_or_cask.url&.using != :homebrew_curl
|
2022-08-07 19:36:06 +02:00
|
|
|
|
2022-09-18 21:27:10 +02:00
|
|
|
domain = Addressable::URI.parse(formula_or_cask.url.to_s)&.domain
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
homebrew_curl_root_domains << domain if domain.present?
|
2021-11-23 23:22:41 -05:00
|
|
|
end
|
Livecheck: Use Homebrew curl based on root domain
At the moment, `#use_homebrew_curl?` can only be true for a
`homepage` or `stable`/cask `url` with `using: :homebrew_curl`. If
the checked URL differs from these URLs, livecheck won't use brewed
curl. This limitation prevents livecheck from using brewed curl for a
`livecheck` block URL that's a string literal (not a symbol for a
`#checkable_url` like `:stable`, `:head`, `:url`). `libzip` was the
original formula referenced in the related brew issue and it meets
this criterion, so it doesn't appear to be handled by the existing
`#use_homebrew_curl?` implementation.
Additionally, the existing behavior can cause livecheck to
unnecessarily use brewed curl for a completely different website
(e.g., `cubelib`, `otf2`). For example, if the `stable` URL has
`using: :homebrew_curl` and the `livecheck` block has `url
:homepage`, livecheck will use brewed curl when checking the
`homepage`. If these are completely different domains/servers, it's
unlikely that we would need to use brewed curl when checking the
`homepage`, so this particular behavior may not be beneficial.
This commit reimplements `use_homebrew_curl?` to apply brewed curl
when the checked URL's root domain is the same as the root domain of
an aforementioned formula/cask URL with `using: :homebrew_curl`. For
example, this looser approach would allow a `livecheck` block
checking `https://www.example.com/downloads/` to use brewed curl if
the `stable` URL was `https://downloads.example.com/example.zip` with
`using: :homebrew_curl`. These could be different servers but, based
on related formulae, this looseness is necessary for the moment.
This approach aims to resolve both issues, allowing brewed curl to be
applied to a slightly broader range of URLs (i.e., not limited to
just the `#checkable_urls`) while also helping to avoid unnecessarily
applying brewed curl when it's less likely to be useful (completely
different domains). Neither approach is perfect but this one may be
more useful in the interim time.
Depending on how this looser approach works in practice, we may want
to consider returning to a stricter approach once we have something
like `using: :homebrew_curl` in `livecheck` blocks (this is
forthcoming). Being explicit in a `livecheck` block is the most
reliable approach (i.e., only use brewed curl when needed), so we
could favor that and pare down the automated approach to only what's
needed to support implicit checks (i.e., with no `livecheck` block).
Of course, it's also possible to drop the automated approach entirely
and simply require a `livecheck` block in this scenario but we can
decide on how to handle this when the time comes.
2022-05-18 16:40:30 -04:00
|
|
|
|
|
|
|
homebrew_curl_root_domains.include?(url_root_domain)
|
2021-11-23 23:22:41 -05:00
|
|
|
end
|
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
# Identifies the latest version of the formula/cask and returns a Hash containing
|
|
|
|
# the version information. Returns nil if a latest version couldn't be found.
|
2022-07-24 15:47:40 +02:00
|
|
|
sig {
|
|
|
|
params(
|
2022-09-25 00:53:44 +02:00
|
|
|
formula_or_cask: T.any(Formula, Cask::Cask),
|
|
|
|
referenced_formula_or_cask: T.nilable(T.any(Formula, Cask::Cask)),
|
|
|
|
livecheck_references: T::Array[T.any(Formula, Cask::Cask)],
|
|
|
|
json: T::Boolean,
|
|
|
|
full_name: T::Boolean,
|
|
|
|
verbose: T::Boolean,
|
|
|
|
debug: T::Boolean,
|
2023-12-12 10:10:18 -08:00
|
|
|
).returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
2022-07-24 15:47:40 +02:00
|
|
|
}
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.latest_version(
|
2022-09-25 00:53:44 +02:00
|
|
|
formula_or_cask,
|
|
|
|
referenced_formula_or_cask: nil,
|
|
|
|
livecheck_references: [],
|
|
|
|
json: false, full_name: false, verbose: false, debug: false
|
2022-07-24 15:47:40 +02:00
|
|
|
)
|
2022-09-25 00:53:44 +02:00
|
|
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
|
|
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
2022-07-27 16:37:31 +02:00
|
|
|
|
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 = formula_or_cask.livecheck_defined?
|
2022-09-25 00:53:44 +02:00
|
|
|
livecheck = formula_or_cask.livecheck
|
|
|
|
referenced_livecheck = referenced_formula_or_cask&.livecheck
|
2022-07-24 17:39:07 +02:00
|
|
|
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
livecheck_options = livecheck.options || referenced_livecheck&.options
|
|
|
|
livecheck_url_options = livecheck_options.url_options.compact
|
2022-09-25 00:53:44 +02:00
|
|
|
livecheck_url = livecheck.url || referenced_livecheck&.url
|
|
|
|
livecheck_regex = livecheck.regex || referenced_livecheck&.regex
|
|
|
|
livecheck_strategy = livecheck.strategy || referenced_livecheck&.strategy
|
|
|
|
livecheck_strategy_block = livecheck.strategy_block || referenced_livecheck&.strategy_block
|
2024-03-20 22:50:14 -04:00
|
|
|
livecheck_throttle = livecheck.throttle || referenced_livecheck&.throttle
|
2022-07-27 18:25:12 +02:00
|
|
|
|
2024-08-23 03:15:57 +01:00
|
|
|
referenced_package = referenced_formula_or_cask || formula_or_cask
|
|
|
|
|
|
|
|
livecheck_url_string = livecheck_url_to_string(livecheck_url, referenced_package) if livecheck_url
|
2022-07-24 15:47:40 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
urls = [livecheck_url_string] if livecheck_url_string
|
2024-08-23 03:15:57 +01:00
|
|
|
urls ||= checkable_urls(referenced_package)
|
2022-07-24 15:47:40 +02:00
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
if debug
|
|
|
|
if formula
|
2024-03-07 16:20:20 +00:00
|
|
|
puts "Formula: #{formula_name(formula, full_name:)}"
|
2022-09-25 00:53:44 +02:00
|
|
|
puts "Head only?: true" if formula.head_only?
|
|
|
|
elsif cask
|
2024-03-07 16:20:20 +00:00
|
|
|
puts "Cask: #{cask_name(formula_or_cask, full_name:)}"
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
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
|
|
|
puts "livecheck block?: #{livecheck_defined ? "Yes" : "No"}"
|
2024-03-20 22:50:14 -04:00
|
|
|
puts "Throttle: #{livecheck_throttle}" if livecheck_throttle
|
2022-09-25 00:53:44 +02:00
|
|
|
|
|
|
|
livecheck_references.each do |ref_formula_or_cask|
|
|
|
|
case ref_formula_or_cask
|
|
|
|
when Formula
|
2024-03-07 16:20:20 +00:00
|
|
|
puts "Formula Ref: #{formula_name(ref_formula_or_cask, full_name:)}"
|
2022-09-25 00:53:44 +02:00
|
|
|
when Cask::Cask
|
2024-03-07 16:20:20 +00:00
|
|
|
puts "Cask Ref: #{cask_name(ref_formula_or_cask, full_name:)}"
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-07-27 21:28:28 +02:00
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
checked_urls = []
|
2022-08-07 18:14:24 +02:00
|
|
|
urls.each_with_index do |original_url, i|
|
2024-09-28 10:22:12 -04:00
|
|
|
url = original_url
|
2022-08-07 18:14:24 +02:00
|
|
|
next if checked_urls.include?(url)
|
|
|
|
|
|
|
|
strategies = Strategy.from_url(
|
|
|
|
url,
|
2024-03-07 16:20:20 +00:00
|
|
|
livecheck_strategy:,
|
2022-08-07 18:14:24 +02:00
|
|
|
regex_provided: livecheck_regex.present?,
|
|
|
|
block_provided: livecheck_strategy_block.present?,
|
|
|
|
)
|
|
|
|
strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first
|
2025-02-19 16:22:25 -05:00
|
|
|
next unless strategy
|
|
|
|
|
|
|
|
strategy_name = livecheck_strategy_names(strategy)
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2024-09-28 10:22:12 -04:00
|
|
|
if strategy.respond_to?(:preprocess_url)
|
|
|
|
url = strategy.preprocess_url(url)
|
|
|
|
next if checked_urls.include?(url)
|
|
|
|
end
|
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
if debug
|
|
|
|
puts
|
|
|
|
if livecheck_url.is_a?(Symbol)
|
|
|
|
# This assumes the URL symbol will fit within the available space
|
|
|
|
puts "URL (#{livecheck_url}):".ljust(18, " ") + original_url
|
2025-01-07 10:27:58 +05:30
|
|
|
elsif original_url.present? && original_url != "None"
|
2022-08-07 18:14:24 +02:00
|
|
|
puts "URL: #{original_url}"
|
|
|
|
end
|
|
|
|
puts "URL (processed): #{url}" if url != original_url
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
puts "URL Options: #{livecheck_url_options}" if livecheck_url_options.present?
|
2022-08-07 18:14:24 +02:00
|
|
|
if strategies.present? && verbose
|
2025-02-19 16:22:25 -05:00
|
|
|
puts "Strategies: #{strategies.map { |s| livecheck_strategy_names(s) }.join(", ")}"
|
2022-07-27 21:28:28 +02:00
|
|
|
end
|
2025-01-07 10:27:58 +05:30
|
|
|
puts "Strategy: #{strategy_name}" if strategy.present?
|
2022-08-07 18:14:24 +02:00
|
|
|
puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present?
|
|
|
|
end
|
2022-07-27 20:43:07 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
if livecheck_strategy.present?
|
|
|
|
if livecheck_url.blank? && strategy.method(:find_versions).parameters.include?([:keyreq, :url])
|
|
|
|
odebug "#{strategy_name} strategy requires a URL"
|
|
|
|
next
|
|
|
|
elsif livecheck_strategy != :page_match && strategies.exclude?(strategy)
|
|
|
|
odebug "#{strategy_name} strategy does not apply to this URL"
|
|
|
|
next
|
2022-07-27 21:28:28 +02:00
|
|
|
end
|
2022-08-07 18:14:24 +02:00
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
next if strategy.blank?
|
2022-07-24 17:39:07 +02:00
|
|
|
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
if (livecheck_homebrew_curl = livecheck_options.homebrew_curl).nil?
|
|
|
|
case strategy_name
|
|
|
|
when "PageMatch", "HeaderMatch"
|
|
|
|
if (homebrew_curl = use_homebrew_curl?(referenced_package, url))
|
|
|
|
livecheck_options = livecheck_options.merge({ homebrew_curl: })
|
|
|
|
livecheck_homebrew_curl = homebrew_curl
|
|
|
|
end
|
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
puts "Homebrew curl?: #{livecheck_homebrew_curl ? "Yes" : "No"}" if debug && !livecheck_homebrew_curl.nil?
|
2022-09-25 00:53:44 +02:00
|
|
|
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
# Only use arguments that the strategy's `#find_versions` method
|
|
|
|
# supports
|
2025-02-15 16:52:19 -08:00
|
|
|
find_versions_parameters = livecheck_find_versions_parameters(strategy)
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
strategy_args = {}
|
|
|
|
strategy_args[:cask] = cask if find_versions_parameters.include?(:cask)
|
|
|
|
strategy_args[:url] = url if find_versions_parameters.include?(:url)
|
|
|
|
strategy_args[:regex] = livecheck_regex if find_versions_parameters.include?(:regex)
|
|
|
|
strategy_args[:options] = livecheck_options if find_versions_parameters.include?(:options)
|
livecheck: Selectively pass args to #find_versions
The existing way of passing values to `#find_versions` methods in
strategies leads to type issues when the Sorbet runtime is enabled.
We've also recently talked about moving away from nilable args when
we can specify a default value but this doesn't work if we pass in a
`nil` value (like we're currently doing).
This commit aims to address both of those areas by better controlling
which arguments we're passing to `#find_versions`. This approach
naively handles `cask`/`url` arguments by special-casing
`ExtractPlist`.
However, we should be checking the strategy's `#find_versions`
method for a `cask` or `url` keyword parameter. The issue is that
`strategy.method(:find_versions).parameters` is returning
`[[:rest, :args], [:block, :blk]]` instead of the actual parameters
like `[[:keyreq, :url], [:key, :regex], [:keyrest, :unused],
[:block, :block]]`.
2023-04-28 17:23:30 -04:00
|
|
|
strategy_args.compact!
|
|
|
|
|
|
|
|
strategy_data = strategy.find_versions(**strategy_args, &livecheck_strategy_block)
|
2022-08-07 18:14:24 +02:00
|
|
|
match_version_map = strategy_data[:matches]
|
|
|
|
regex = strategy_data[:regex]
|
|
|
|
messages = strategy_data[:messages]
|
|
|
|
checked_urls << url
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
if messages.is_a?(Array) && match_version_map.blank?
|
|
|
|
puts messages unless json
|
|
|
|
next if i + 1 < urls.length
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2024-03-07 16:20:20 +00:00
|
|
|
return status_hash(formula_or_cask, "error", messages, full_name:, verbose:)
|
2022-08-07 18:14:24 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if debug
|
|
|
|
if strategy_data[:url].present? && strategy_data[:url] != url
|
|
|
|
puts "URL (strategy): #{strategy_data[:url]}"
|
|
|
|
end
|
|
|
|
puts "URL (final): #{strategy_data[:final_url]}" if strategy_data[:final_url].present?
|
|
|
|
if strategy_data[:regex].present? && strategy_data[:regex] != livecheck_regex
|
|
|
|
puts "Regex (strategy): #{strategy_data[:regex].inspect}"
|
2022-07-27 21:28:28 +02:00
|
|
|
end
|
2022-08-07 18:14:24 +02:00
|
|
|
puts "Cached?: Yes" if strategy_data[:cached] == true
|
|
|
|
end
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
match_version_map.delete_if do |_match, version|
|
|
|
|
next true if version.blank?
|
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
|
|
|
next false if livecheck_defined
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
UNSTABLE_VERSION_KEYWORDS.any? do |rejection|
|
|
|
|
version.to_s.include?(rejection)
|
2022-07-27 21:28:28 +02:00
|
|
|
end
|
2022-08-07 18:14:24 +02:00
|
|
|
end
|
|
|
|
next if match_version_map.blank?
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
if debug
|
|
|
|
puts
|
|
|
|
puts "Matched Versions:"
|
2022-07-24 17:39:07 +02:00
|
|
|
|
2022-08-07 18:14:24 +02:00
|
|
|
if verbose
|
|
|
|
match_version_map.each do |match, version|
|
|
|
|
puts "#{match} => #{version.inspect}"
|
2022-07-24 17:39:07 +02:00
|
|
|
end
|
2022-08-07 18:14:24 +02:00
|
|
|
else
|
|
|
|
puts match_version_map.values.join(", ")
|
2022-07-27 21:28:28 +02:00
|
|
|
end
|
2022-08-07 18:14:24 +02:00
|
|
|
end
|
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
version_info = {
|
|
|
|
latest: Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) }),
|
2022-08-07 18:14:24 +02:00
|
|
|
}
|
|
|
|
|
2024-03-20 22:50:14 -04:00
|
|
|
if livecheck_throttle
|
|
|
|
match_version_map.keep_if { |_match, version| version.patch.to_i.modulo(livecheck_throttle).zero? }
|
2024-03-19 11:17:00 -04:00
|
|
|
version_info[:latest_throttled] = if match_version_map.blank?
|
|
|
|
nil
|
|
|
|
else
|
|
|
|
Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) })
|
|
|
|
end
|
|
|
|
|
|
|
|
if debug
|
|
|
|
puts
|
|
|
|
puts "Matched Throttled Versions:"
|
|
|
|
|
|
|
|
if verbose
|
|
|
|
match_version_map.each do |match, version|
|
|
|
|
puts "#{match} => #{version.inspect}"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
puts match_version_map.values.join(", ")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
if json && verbose
|
|
|
|
version_info[:meta] = {}
|
2022-08-07 19:14:13 +02:00
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
if livecheck_references.present?
|
|
|
|
version_info[:meta][:references] = livecheck_references.map do |ref_formula_or_cask|
|
|
|
|
case ref_formula_or_cask
|
|
|
|
when Formula
|
2024-03-07 16:20:20 +00:00
|
|
|
{ formula: formula_name(ref_formula_or_cask, full_name:) }
|
2022-09-25 00:53:44 +02:00
|
|
|
when Cask::Cask
|
2024-03-07 16:20:20 +00:00
|
|
|
{ cask: cask_name(ref_formula_or_cask, full_name:) }
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
|
|
|
end
|
2022-07-27 18:25:12 +02:00
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
|
2025-01-07 10:27:58 +05:30
|
|
|
if url != "None"
|
|
|
|
version_info[:meta][:url] = {}
|
|
|
|
version_info[:meta][:url][:symbol] = livecheck_url if livecheck_url.is_a?(Symbol) && livecheck_url_string
|
|
|
|
version_info[:meta][:url][:original] = original_url
|
|
|
|
version_info[:meta][:url][:processed] = url if url != original_url
|
|
|
|
if strategy_data[:url].present? && strategy_data[:url] != url
|
|
|
|
version_info[:meta][:url][:strategy] = strategy_data[:url]
|
|
|
|
end
|
|
|
|
version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data[:final_url]
|
2025-02-04 10:30:16 -05:00
|
|
|
version_info[:meta][:url][:options] = livecheck_url_options if livecheck_url_options.present?
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
2025-01-07 10:27:58 +05:30
|
|
|
version_info[:meta][:strategy] = strategy_name if strategy.present?
|
2025-02-19 16:22:25 -05:00
|
|
|
version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names(s) } if strategies.present?
|
2022-09-25 00:53:44 +02:00
|
|
|
version_info[:meta][:regex] = regex.inspect if regex.present?
|
|
|
|
version_info[:meta][:cached] = true if strategy_data[:cached] == true
|
2024-03-20 22:50:14 -04:00
|
|
|
version_info[:meta][:throttle] = livecheck_throttle if livecheck_throttle
|
2022-07-27 21:28:28 +02:00
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
|
|
|
|
return version_info
|
2022-07-24 15:47:40 +02:00
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
nil
|
2022-07-24 15:47:40 +02:00
|
|
|
end
|
2023-12-12 10:10:18 -08:00
|
|
|
|
2022-09-27 00:59:37 -07:00
|
|
|
# Identifies the latest version of a resource and returns a Hash containing the
|
|
|
|
# version information. Returns nil if a latest version couldn't be found.
|
2021-01-17 22:45:55 -08:00
|
|
|
sig {
|
2021-01-04 13:41:19 -08:00
|
|
|
params(
|
2022-12-18 18:11:51 -05:00
|
|
|
resource: Resource,
|
|
|
|
formula_latest: String,
|
|
|
|
json: T::Boolean,
|
2025-01-07 01:46:24 +05:30
|
|
|
full_name: T::Boolean,
|
2022-12-18 18:11:51 -05:00
|
|
|
debug: T::Boolean,
|
|
|
|
quiet: T::Boolean,
|
|
|
|
verbose: T::Boolean,
|
2023-12-12 10:10:18 -08:00
|
|
|
).returns(T::Hash[Symbol, T.untyped])
|
2021-01-17 22:45:55 -08:00
|
|
|
}
|
2024-08-23 03:15:57 +01:00
|
|
|
def self.resource_version(
|
2022-09-25 00:53:44 +02:00
|
|
|
resource,
|
2022-12-18 18:11:51 -05:00
|
|
|
formula_latest,
|
2022-09-25 00:53:44 +02:00
|
|
|
json: false,
|
2025-01-07 01:46:24 +05:30
|
|
|
full_name: false,
|
2022-09-25 00:53:44 +02:00
|
|
|
debug: false,
|
|
|
|
quiet: false,
|
|
|
|
verbose: false
|
2021-07-19 11:21:29 -04:00
|
|
|
)
|
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 = resource.livecheck_defined?
|
2020-09-02 12:24:21 -07:00
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
if debug
|
|
|
|
puts "\n\n"
|
|
|
|
puts "Resource: #{resource.name}"
|
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
|
|
|
puts "livecheck block?: #{livecheck_defined ? "Yes" : "No"}"
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
resource_version_info = {}
|
|
|
|
|
|
|
|
livecheck = resource.livecheck
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
livecheck_options = livecheck.options
|
|
|
|
livecheck_url_options = livecheck_options.url_options.compact
|
2025-01-06 12:56:25 +05:30
|
|
|
livecheck_reference = livecheck.formula
|
2022-09-25 22:21:04 +05:00
|
|
|
livecheck_url = livecheck.url
|
2022-09-25 00:53:44 +02:00
|
|
|
livecheck_regex = livecheck.regex
|
|
|
|
livecheck_strategy = livecheck.strategy
|
|
|
|
livecheck_strategy_block = livecheck.strategy_block
|
2021-07-19 11:21:29 -04:00
|
|
|
|
2024-10-24 09:00:18 -04:00
|
|
|
livecheck_url_string = livecheck_url_to_string(livecheck_url, resource) if livecheck_url
|
2021-01-12 15:00:49 -05:00
|
|
|
|
|
|
|
urls = [livecheck_url_string] if livecheck_url_string
|
2025-01-06 12:56:25 +05:30
|
|
|
urls = ["None"] if livecheck_reference == :parent
|
2022-09-25 00:53:44 +02:00
|
|
|
urls ||= checkable_urls(resource)
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2021-08-13 16:29:06 -04:00
|
|
|
checked_urls = []
|
2020-08-08 07:10:48 +05:30
|
|
|
urls.each_with_index do |original_url, i|
|
2022-12-19 18:15:51 -05:00
|
|
|
url = original_url.gsub(Constants::LATEST_VERSION, formula_latest)
|
2021-08-13 16:29:06 -04:00
|
|
|
next if checked_urls.include?(url)
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2020-12-05 11:49:47 -05:00
|
|
|
strategies = Strategy.from_url(
|
|
|
|
url,
|
2024-03-07 16:20:20 +00:00
|
|
|
livecheck_strategy:,
|
2020-12-05 11:49:47 -05:00
|
|
|
regex_provided: livecheck_regex.present?,
|
2021-07-19 11:21:29 -04:00
|
|
|
block_provided: livecheck_strategy_block.present?,
|
2020-12-05 11:49:47 -05:00
|
|
|
)
|
2021-04-04 03:00:34 +02:00
|
|
|
strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first
|
2025-03-10 13:21:00 -04:00
|
|
|
next if strategy.blank? && livecheck_reference != :parent
|
2025-02-19 16:22:25 -05:00
|
|
|
|
2025-03-10 13:21:00 -04:00
|
|
|
strategy_name = livecheck_strategy_names(strategy) if strategy.present?
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2024-09-28 10:22:12 -04:00
|
|
|
if strategy.respond_to?(:preprocess_url)
|
|
|
|
url = strategy.preprocess_url(url)
|
|
|
|
next if checked_urls.include?(url)
|
|
|
|
end
|
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
if debug
|
2021-08-13 16:29:06 -04:00
|
|
|
puts
|
|
|
|
if livecheck_url.is_a?(Symbol)
|
|
|
|
# This assumes the URL symbol will fit within the available space
|
|
|
|
puts "URL (#{livecheck_url}):".ljust(18, " ") + original_url
|
2025-01-07 10:27:58 +05:30
|
|
|
elsif original_url.present? && original_url != "None"
|
2021-08-13 16:29:06 -04:00
|
|
|
puts "URL: #{original_url}"
|
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
puts "URL (processed): #{url}" if url != original_url
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
puts "URL Options: #{livecheck_url_options}" if livecheck_url_options.present?
|
2020-12-14 14:30:36 +01:00
|
|
|
if strategies.present? && verbose
|
2025-02-19 16:22:25 -05:00
|
|
|
puts "Strategies: #{strategies.map { |s| livecheck_strategy_names(s) }.join(", ")}"
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
2025-01-07 10:27:58 +05:30
|
|
|
puts "Strategy: #{strategy_name}" if strategy.present?
|
2020-08-08 07:10:48 +05:30
|
|
|
puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present?
|
2025-01-07 01:46:24 +05:30
|
|
|
if livecheck_reference == :parent
|
|
|
|
puts "Formula Ref: #{full_name ? resource.owner.full_name : resource.owner.name} (parent)"
|
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
2021-04-04 03:00:34 +02:00
|
|
|
if livecheck_strategy.present?
|
2022-06-24 00:08:25 -04:00
|
|
|
if livecheck_url.blank? && strategy.method(:find_versions).parameters.include?([:keyreq, :url])
|
2021-04-04 03:00:34 +02:00
|
|
|
odebug "#{strategy_name} strategy requires a URL"
|
|
|
|
next
|
2021-11-19 23:37:29 -05:00
|
|
|
elsif livecheck_strategy != :page_match && strategies.exclude?(strategy)
|
2021-04-04 03:00:34 +02:00
|
|
|
odebug "#{strategy_name} strategy does not apply to this URL"
|
|
|
|
next
|
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
2025-01-06 12:56:25 +05:30
|
|
|
puts if debug && strategy.blank? && livecheck_reference != :parent
|
|
|
|
next if strategy.blank? && livecheck_reference != :parent
|
2020-08-08 07:10:48 +05:30
|
|
|
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
if debug && !(livecheck_homebrew_curl = livecheck_options.homebrew_curl).nil?
|
|
|
|
puts "Homebrew curl?: #{livecheck_homebrew_curl ? "Yes" : "No"}"
|
|
|
|
end
|
|
|
|
|
2025-01-06 12:56:25 +05:30
|
|
|
if livecheck_reference == :parent
|
|
|
|
match_version_map = { formula_latest => Version.new(formula_latest) }
|
|
|
|
cached = true
|
|
|
|
else
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
# Only use arguments that the strategy's `#find_versions` method
|
|
|
|
# supports
|
2025-02-15 16:52:19 -08:00
|
|
|
find_versions_parameters = livecheck_find_versions_parameters(strategy)
|
livecheck: Add Options class
This adds a `Livecheck::Options` class, which is intended to house
various configuration options that are set in `livecheck` blocks,
conditionally set by livecheck at runtime, etc. The general idea is
that when we add features involving configurations options (e.g., for
livecheck, strategies, curl, etc.), we can make changes to `Options`
without needing to modify parameters for strategy `find_versions`
methods, `Strategy` methods like `page_headers` and `page_content`,
etc. This is something that I've been trying to improve over the years
and `Options` should help to reduce maintenance overhead in this area
while also strengthening type signatures.
`Options` replaces the existing `homebrew_curl` option (which related
strategies pass to `Strategy` methods and on to `curl_args`) and the
new `url_options` (which contains `post_form` or `post_json` values
that are used to make `POST` requests). I recently added `url_options`
as a temporary way of enabling `POST` support without `Options` but
this restores the original `Options`-based implementation.
Along the way, I added a `homebrew_curl` parameter to the `url` DSL
method, allowing us to set an explicit value in `livecheck` blocks.
This is something that we've needed in some cases but I also intend
to replace implicit/inferred `homebrew_curl` usage with explicit
values in `livecheck` blocks once this is available for use. My
intention is to eventually remove the implicit behavior and only rely
on explicit values. That will align with how `homebrew_curl` options
work for other URLs and makes the behavior clear just from looking at
the `livecheck` block.
Lastly, this removes the `unused` rest parameter from `find_versions`
methods. I originally added `unused` as a way of handling parameters
that some `find_versions` methods have but others don't (e.g., `cask`
in `ExtractPlist`), as this allowed us to pass various arguments to
`find_versions` methods without worrying about whether a particular
parameter is available. This isn't an ideal solution and I originally
wanted to handle this situation by only passing expected arguments to
`find_versions` methods but there was a technical issue standing in
the way. I recently found an answer to the issue, so this also
replaces the existing `ExtractPlist` special case with generic logic
that checks the parameters for a strategy's `find_versions` method
and only passes expected arguments.
Replacing the aforementioned `find_versions` parameters with `Options`
ensures that the remaining parameters are fairly consistent across
strategies and any differences are handled by the aforementioned
logic. Outside of `ExtractPlist`, the only other difference is that
some `find_versions` methods have a `provided_content` parameter but
that's currently only used by tests (though it's intended for caching
support in the future). I will be renaming that parameter to `content`
in an upcoming PR and expanding it to the other strategies, which
should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
|
|
|
strategy_args = {}
|
|
|
|
strategy_args[:url] = url if find_versions_parameters.include?(:url)
|
|
|
|
strategy_args[:regex] = livecheck_regex if find_versions_parameters.include?(:regex)
|
|
|
|
strategy_args[:options] = livecheck_options if find_versions_parameters.include?(:options)
|
|
|
|
strategy_args.compact!
|
2025-01-06 12:56:25 +05:30
|
|
|
|
|
|
|
strategy_data = strategy.find_versions(**strategy_args, &livecheck_strategy_block)
|
|
|
|
match_version_map = strategy_data[:matches]
|
|
|
|
regex = strategy_data[:regex]
|
|
|
|
messages = strategy_data[:messages]
|
|
|
|
cached = strategy_data[:cached]
|
|
|
|
end
|
livecheck: Selectively pass args to #find_versions
The existing way of passing values to `#find_versions` methods in
strategies leads to type issues when the Sorbet runtime is enabled.
We've also recently talked about moving away from nilable args when
we can specify a default value but this doesn't work if we pass in a
`nil` value (like we're currently doing).
This commit aims to address both of those areas by better controlling
which arguments we're passing to `#find_versions`. This approach
naively handles `cask`/`url` arguments by special-casing
`ExtractPlist`.
However, we should be checking the strategy's `#find_versions`
method for a `cask` or `url` keyword parameter. The issue is that
`strategy.method(:find_versions).parameters` is returning
`[[:rest, :args], [:block, :blk]]` instead of the actual parameters
like `[[:keyreq, :url], [:key, :regex], [:keyrest, :unused],
[:block, :block]]`.
2023-04-28 17:23:30 -04:00
|
|
|
|
2021-08-13 16:29:06 -04:00
|
|
|
checked_urls << url
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2021-01-04 13:41:19 -08:00
|
|
|
if messages.is_a?(Array) && match_version_map.blank?
|
|
|
|
puts messages unless json
|
2020-08-08 07:10:48 +05:30
|
|
|
next if i + 1 < urls.length
|
|
|
|
|
2024-03-07 16:20:20 +00:00
|
|
|
return status_hash(resource, "error", messages, verbose:)
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
if debug
|
2025-01-06 12:56:25 +05:30
|
|
|
if strategy_data&.dig(:url).present? && strategy_data[:url] != url
|
2021-11-16 12:39:27 -05:00
|
|
|
puts "URL (strategy): #{strategy_data[:url]}"
|
|
|
|
end
|
2025-01-06 12:56:25 +05:30
|
|
|
puts "URL (final): #{strategy_data[:final_url]}" if strategy_data&.dig(:final_url).present?
|
|
|
|
if strategy_data&.dig(:regex).present? && strategy_data[:regex] != livecheck_regex
|
2021-11-16 12:39:27 -05:00
|
|
|
puts "Regex (strategy): #{strategy_data[:regex].inspect}"
|
|
|
|
end
|
2025-01-06 12:56:25 +05:30
|
|
|
puts "Cached?: Yes" if cached == true
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
match_version_map.delete_if do |_match, version|
|
|
|
|
next true if version.blank?
|
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
|
|
|
next false if livecheck_defined
|
2020-08-08 07:10:48 +05:30
|
|
|
|
|
|
|
UNSTABLE_VERSION_KEYWORDS.any? do |rejection|
|
|
|
|
version.to_s.include?(rejection)
|
|
|
|
end
|
|
|
|
end
|
2021-04-04 03:00:34 +02:00
|
|
|
next if match_version_map.blank?
|
|
|
|
|
|
|
|
if debug
|
2020-08-08 07:10:48 +05:30
|
|
|
puts
|
|
|
|
puts "Matched Versions:"
|
|
|
|
|
2020-12-14 14:30:36 +01:00
|
|
|
if verbose
|
2020-08-08 07:10:48 +05:30
|
|
|
match_version_map.each do |match, version|
|
|
|
|
puts "#{match} => #{version.inspect}"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
puts match_version_map.values.join(", ")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-05-01 08:08:19 +02:00
|
|
|
res_current = T.must(resource.version)
|
2022-09-25 00:53:44 +02:00
|
|
|
res_latest = Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(resource, v) })
|
2020-08-08 07:10:48 +05:30
|
|
|
|
2025-02-19 15:06:00 -05:00
|
|
|
return status_hash(resource, "error", [NO_VERSIONS_MSG], verbose:) if res_latest.blank?
|
2021-01-12 15:00:49 -05:00
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
is_outdated = res_current < res_latest
|
|
|
|
is_newer_than_upstream = res_current > res_latest
|
2021-07-19 11:21:29 -04:00
|
|
|
|
2022-09-25 00:53:44 +02:00
|
|
|
resource_version_info = {
|
|
|
|
resource: resource.name,
|
|
|
|
version: {
|
|
|
|
current: res_current.to_s,
|
|
|
|
latest: res_latest.to_s,
|
|
|
|
outdated: is_outdated,
|
|
|
|
newer_than_upstream: is_newer_than_upstream,
|
|
|
|
},
|
|
|
|
}
|
2021-01-12 15:00:49 -05:00
|
|
|
|
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
|
|
|
resource_version_info[:meta] = {
|
|
|
|
livecheck_defined: livecheck_defined,
|
|
|
|
}
|
2025-01-07 02:08:01 +05:30
|
|
|
if livecheck_reference == :parent
|
2025-01-07 01:46:24 +05:30
|
|
|
resource_version_info[:meta][:references] =
|
2025-01-07 10:27:58 +05:30
|
|
|
[{ formula: full_name ? resource.owner.full_name : resource.owner.name, symbol: :parent }]
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
2025-01-07 02:08:01 +05:30
|
|
|
if url != "None"
|
|
|
|
resource_version_info[:meta][:url] = {}
|
|
|
|
if livecheck_url.is_a?(Symbol) && livecheck_url_string
|
|
|
|
resource_version_info[:meta][:url][:symbol] = livecheck_url
|
|
|
|
end
|
|
|
|
resource_version_info[:meta][:url][:original] = original_url
|
|
|
|
resource_version_info[:meta][:url][:processed] = url if url != original_url
|
|
|
|
if strategy_data&.dig(:url).present? && strategy_data[:url] != url
|
|
|
|
resource_version_info[:meta][:url][:strategy] = strategy_data[:url]
|
|
|
|
end
|
|
|
|
resource_version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data&.dig(:final_url)
|
2025-02-04 10:30:16 -05:00
|
|
|
resource_version_info[:meta][:url][:options] = livecheck_url_options if livecheck_url_options.present?
|
2022-09-25 00:53:44 +02:00
|
|
|
end
|
2025-01-07 10:27:58 +05:30
|
|
|
resource_version_info[:meta][:strategy] = strategy_name if strategy.present?
|
2022-09-25 00:53:44 +02:00
|
|
|
if strategies.present?
|
2025-02-19 16:22:25 -05:00
|
|
|
resource_version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names(s) }
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
resource_version_info[:meta][:regex] = regex.inspect if regex.present?
|
2025-01-06 12:56:25 +05:30
|
|
|
resource_version_info[:meta][:cached] = true if cached == true
|
2022-09-25 00:53:44 +02:00
|
|
|
rescue => e
|
|
|
|
Homebrew.failed = true
|
|
|
|
if json
|
2024-03-07 16:20:20 +00:00
|
|
|
status_hash(resource, "error", [e.to_s], verbose:)
|
2022-09-25 00:53:44 +02:00
|
|
|
elsif !quiet
|
|
|
|
onoe "#{Tty.blue}#{resource.name}#{Tty.reset}: #{e}"
|
2024-07-15 13:44:01 -04:00
|
|
|
if debug && !e.is_a?(Livecheck::Error)
|
|
|
|
require "utils/backtrace"
|
|
|
|
$stderr.puts Utils::Backtrace.clean(e)
|
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
nil
|
|
|
|
end
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
2022-09-25 00:53:44 +02:00
|
|
|
resource_version_info
|
2020-08-08 07:10:48 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|