| 
									
										
										
										
											2024-07-06 10:00:47 -04:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  | require "utils/curl" | 
					
						
							| 
									
										
											  
											
												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
										 |  |  | require "livecheck/options" | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | module Homebrew | 
					
						
							|  |  |  |   module Livecheck | 
					
						
							|  |  |  |     # The `Livecheck::Strategy` module contains the various strategies as well | 
					
						
							|  |  |  |     # as some general-purpose methods for working with them. Within the context | 
					
						
							|  |  |  |     # of the `brew livecheck` command, strategies are established procedures | 
					
						
							|  |  |  |     # for finding new software versions at a given source. | 
					
						
							|  |  |  |     module Strategy | 
					
						
							| 
									
										
										
										
											2023-05-02 23:58:51 +02:00
										 |  |  |       extend Utils::Curl | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # {Strategy} priorities informally range from 1 to 10, where 10 is the | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       # highest priority. 5 is the default priority because it's roughly in | 
					
						
							|  |  |  |       # the middle of this range. Strategies with a priority of 0 (or lower) | 
					
						
							|  |  |  |       # are ignored. | 
					
						
							|  |  |  |       DEFAULT_PRIORITY = 5
 | 
					
						
							| 
									
										
										
										
											2021-06-04 13:12:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  |       # cURL's default `--connect-timeout` value can be up to two minutes, so | 
					
						
							|  |  |  |       # we need to use a more reasonable duration (in seconds) to avoid a | 
					
						
							|  |  |  |       # lengthy wait when a connection can't be established. | 
					
						
							|  |  |  |       CURL_CONNECT_TIMEOUT = 10
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # cURL does not set a default `--max-time` value, so we provide a value | 
					
						
							|  |  |  |       # to ensure cURL will time out in a reasonable amount of time. | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       CURL_MAX_TIME = T.let(CURL_CONNECT_TIMEOUT + 5, Integer) | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # The `curl` process will sometimes hang indefinitely (despite setting | 
					
						
							|  |  |  |       # the `--max-time` argument) and it needs to be quit for livecheck to | 
					
						
							|  |  |  |       # continue. This value is used to set the `timeout` argument on | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # `Utils::Curl` method calls in {Strategy}. | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       CURL_PROCESS_TIMEOUT = T.let(CURL_MAX_TIME + 5, Integer) | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-22 13:02:13 -04:00
										 |  |  |       # The maximum number of redirections that `curl` should allow. | 
					
						
							|  |  |  |       MAX_REDIRECTIONS = 5
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # This value is passed to `#parse_curl_output` to ensure that the limit | 
					
						
							|  |  |  |       # for the number of responses it will parse corresponds to the maximum | 
					
						
							|  |  |  |       # number of responses in this context. The `+ 1` here accounts for the | 
					
						
							|  |  |  |       # situation where there are exactly `MAX_REDIRECTIONS` number of | 
					
						
							|  |  |  |       # redirections, followed by a final `200 OK` response. | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       MAX_PARSE_ITERATIONS = T.let(MAX_REDIRECTIONS + 1, Integer) | 
					
						
							| 
									
										
										
										
											2022-04-22 13:02:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # Baseline `curl` arguments used in {Strategy} methods. | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       DEFAULT_CURL_ARGS = T.let([ | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  |         # Follow redirections to handle mirrors, relocations, etc. | 
					
						
							|  |  |  |         "--location", | 
					
						
							| 
									
										
										
										
											2022-04-22 13:02:13 -04:00
										 |  |  |         "--max-redirs", MAX_REDIRECTIONS.to_s, | 
					
						
							| 
									
										
										
										
											2021-12-30 16:07:29 -05:00
										 |  |  |         # Avoid progress bar text, so we can reliably identify `curl` error | 
					
						
							|  |  |  |         # messages in output | 
					
						
							| 
									
										
										
										
											2022-04-22 13:02:13 -04:00
										 |  |  |         "--silent" | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       ].freeze, T::Array[String]) | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # `curl` arguments used in `Strategy#page_content` method. | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       PAGE_CONTENT_CURL_ARGS = T.let(([ | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  |         "--compressed", | 
					
						
							| 
									
										
										
										
											2024-02-25 02:30:33 +05:30
										 |  |  |         # Return an error when the HTTP response code is 400 or greater but | 
					
						
							|  |  |  |         # continue to return body content | 
					
						
							| 
									
										
										
										
											2024-02-24 00:19:24 +05:30
										 |  |  |         "--fail-with-body", | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  |         # Include HTTP response headers in output, so we can identify the | 
					
						
							|  |  |  |         # final URL after any redirections | 
					
						
							|  |  |  |         "--include", | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       ] + DEFAULT_CURL_ARGS).freeze, T::Array[String]) | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # Baseline `curl` options used in {Strategy} methods. | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       DEFAULT_CURL_OPTIONS = T.let({ | 
					
						
							| 
									
										
										
										
											2021-09-06 22:56:25 -04:00
										 |  |  |         print_stdout:    false, | 
					
						
							|  |  |  |         print_stderr:    false, | 
					
						
							|  |  |  |         debug:           false, | 
					
						
							|  |  |  |         verbose:         false, | 
					
						
							|  |  |  |         timeout:         CURL_PROCESS_TIMEOUT, | 
					
						
							|  |  |  |         connect_timeout: CURL_CONNECT_TIMEOUT, | 
					
						
							|  |  |  |         max_time:        CURL_MAX_TIME, | 
					
						
							|  |  |  |         retries:         0, | 
					
						
							| 
									
										
										
										
											2024-07-04 20:09:36 -04:00
										 |  |  |       }.freeze, T::Hash[Symbol, T.untyped]) | 
					
						
							| 
									
										
										
										
											2021-06-04 13:16:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 13:20:12 -04:00
										 |  |  |       # A regex used to identify a tarball extension at the end of a string. | 
					
						
							| 
									
										
										
										
											2021-08-17 19:15:07 -04:00
										 |  |  |       TARBALL_EXTENSION_REGEX = /
 | 
					
						
							|  |  |  |         \.t | 
					
						
							|  |  |  |         (?:ar(?:\.(?:bz2|gz|lz|lzma|lzo|xz|Z|zst))?| | 
					
						
							|  |  |  |         b2|bz2?|z2|az|gz|lz|lzma|xz|Z|aZ|zst) | 
					
						
							|  |  |  |         $ | 
					
						
							| 
									
										
										
										
											2024-01-18 22:18:42 +00:00
										 |  |  |       /ix
 | 
					
						
							| 
									
										
										
										
											2021-07-28 13:20:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 11:09:55 -04:00
										 |  |  |       # An error message to use when a `strategy` block returns a value of | 
					
						
							|  |  |  |       # an inappropriate type. | 
					
						
							|  |  |  |       INVALID_BLOCK_RETURN_VALUE_MSG = "Return value of a strategy block must be a string or array of strings." | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # Creates and/or returns a `@strategies` `Hash`, which maps a snake | 
					
						
							|  |  |  |       # case strategy name symbol (e.g. `:page_match`) to the associated | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # strategy. | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       # | 
					
						
							|  |  |  |       # At present, this should only be called after tap strategies have been | 
					
						
							|  |  |  |       # loaded, otherwise livecheck won't be able to use them. | 
					
						
							|  |  |  |       # @return [Hash] | 
					
						
							| 
									
										
										
										
											2021-08-10 18:24:51 -04:00
										 |  |  |       sig { returns(T::Hash[Symbol, T.untyped]) } | 
					
						
							| 
									
										
										
										
											2025-02-08 16:42:45 -08:00
										 |  |  |       def self.strategies | 
					
						
							| 
									
										
										
										
											2024-07-06 10:00:47 -04:00
										 |  |  |         @strategies ||= T.let(Strategy.constants.sort.each_with_object({}) do |const_symbol, hash| | 
					
						
							| 
									
										
										
										
											2021-08-09 18:18:12 -04:00
										 |  |  |           constant = Strategy.const_get(const_symbol) | 
					
						
							|  |  |  |           next unless constant.is_a?(Class) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-07 10:11:59 -08:00
										 |  |  |           key = Utils.underscore(const_symbol).to_sym | 
					
						
							| 
									
										
										
										
											2024-07-06 10:00:47 -04:00
										 |  |  |           hash[key] = constant | 
					
						
							|  |  |  |         end, T.nilable(T::Hash[Symbol, T.untyped])) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       end | 
					
						
							|  |  |  |       private_class_method :strategies | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # Returns the strategy that corresponds to the provided `Symbol` (or | 
					
						
							|  |  |  |       # `nil` if there is no matching strategy). | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # @param symbol [Symbol, nil] the strategy name in snake case as a | 
					
						
							|  |  |  |       #   `Symbol` (e.g. `:page_match`) | 
					
						
							|  |  |  |       # @return [Class, nil] | 
					
						
							| 
									
										
										
										
											2022-01-27 12:23:40 -05:00
										 |  |  |       sig { params(symbol: T.nilable(Symbol)).returns(T.untyped) } | 
					
						
							| 
									
										
										
										
											2025-02-08 16:42:45 -08:00
										 |  |  |       def self.from_symbol(symbol) | 
					
						
							| 
									
										
										
										
											2021-08-10 18:24:51 -04:00
										 |  |  |         strategies[symbol] if symbol.present? | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Returns an array of strategies that apply to the provided URL. | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       # @param url [String] the URL to check for matching strategies | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # @param livecheck_strategy [Symbol] a strategy symbol from the | 
					
						
							|  |  |  |       #   `livecheck` block | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |       # @param regex_provided [Boolean] whether a regex is provided in the | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       #   `livecheck` block | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # @param block_provided [Boolean] whether a `strategy` block is provided | 
					
						
							|  |  |  |       #   in the `livecheck` block | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |       # @return [Array] | 
					
						
							| 
									
										
										
										
											2021-08-10 18:24:51 -04:00
										 |  |  |       sig { | 
					
						
							|  |  |  |         params( | 
					
						
							|  |  |  |           url:                String, | 
					
						
							|  |  |  |           livecheck_strategy: T.nilable(Symbol), | 
					
						
							|  |  |  |           regex_provided:     T::Boolean, | 
					
						
							|  |  |  |           block_provided:     T::Boolean, | 
					
						
							|  |  |  |         ).returns(T::Array[T.untyped]) | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-02-08 16:42:45 -08:00
										 |  |  |       def self.from_url(url, livecheck_strategy: nil, regex_provided: false, block_provided: false) | 
					
						
							| 
									
										
										
										
											2023-02-27 17:50:13 -05:00
										 |  |  |         usable_strategies = strategies.select do |strategy_symbol, strategy| | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |           if strategy == PageMatch | 
					
						
							| 
									
										
										
										
											2023-02-23 12:40:07 -05:00
										 |  |  |             # Only treat the strategy as usable if the `livecheck` block | 
					
						
							|  |  |  |             # contains a regex and/or `strategy` block | 
					
						
							| 
									
										
										
										
											2021-01-07 13:49:05 -08:00
										 |  |  |             next if !regex_provided && !block_provided | 
					
						
							| 
									
										
										
										
											2023-03-02 15:19:00 -05:00
										 |  |  |           elsif [Json, Xml, Yaml].include?(strategy) | 
					
						
							| 
									
										
										
										
											2023-02-23 12:40:07 -05:00
										 |  |  |             # Only treat the strategy as usable if the `livecheck` block | 
					
						
							| 
									
										
										
										
											2023-02-27 17:50:13 -05:00
										 |  |  |             # specifies the strategy and contains a `strategy` block | 
					
						
							|  |  |  |             next if (livecheck_strategy != strategy_symbol) || !block_provided | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |           elsif strategy.const_defined?(:PRIORITY) && | 
					
						
							| 
									
										
										
										
											2023-04-01 18:56:42 -07:00
										 |  |  |                 !strategy.const_get(:PRIORITY).positive? && | 
					
						
							| 
									
										
										
										
											2023-02-27 18:45:49 -05:00
										 |  |  |                 livecheck_strategy != strategy_symbol | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |             # Ignore strategies with a priority of 0 or lower, unless the | 
					
						
							|  |  |  |             # strategy is specified in the `livecheck` block | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |           strategy.respond_to?(:match?) && strategy.match?(url) | 
					
						
							| 
									
										
										
										
											2023-02-27 17:50:13 -05:00
										 |  |  |         end.values | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |         # Sort usable strategies in descending order by priority, using the | 
					
						
							|  |  |  |         # DEFAULT_PRIORITY when a strategy doesn't contain a PRIORITY constant | 
					
						
							|  |  |  |         usable_strategies.sort_by do |strategy| | 
					
						
							| 
									
										
										
										
											2023-04-01 18:56:42 -07:00
										 |  |  |           (strategy.const_defined?(:PRIORITY) ? -strategy.const_get(:PRIORITY) : -DEFAULT_PRIORITY) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-12-12 21:56:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |       # Creates `curl` `--data` or `--json` arguments (for `POST` requests`) | 
					
						
							|  |  |  |       # from related `livecheck` block `url` options. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @param post_form [Hash, nil] data to encode using `URI::encode_www_form` | 
					
						
							|  |  |  |       # @param post_json [Hash, nil] data to encode using `JSON::generate` | 
					
						
							|  |  |  |       # @return [Array] | 
					
						
							|  |  |  |       sig { | 
					
						
							|  |  |  |         params( | 
					
						
							| 
									
										
										
										
											2025-02-21 21:54:29 -05:00
										 |  |  |           post_form: T.nilable(T::Hash[Symbol, String]), | 
					
						
							|  |  |  |           post_json: T.nilable(T::Hash[Symbol, String]), | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |         ).returns(T::Array[String]) | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-02-08 16:42:45 -08:00
										 |  |  |       def self.post_args(post_form: nil, post_json: nil) | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |         if post_form.present? | 
					
						
							|  |  |  |           require "uri" | 
					
						
							|  |  |  |           ["--data", URI.encode_www_form(post_form)] | 
					
						
							|  |  |  |         elsif post_json.present? | 
					
						
							|  |  |  |           require "json" | 
					
						
							|  |  |  |           ["--json", JSON.generate(post_json)] | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           [] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # Collects HTTP response headers, starting with the provided URL. | 
					
						
							|  |  |  |       # Redirections will be followed and all the response headers are | 
					
						
							|  |  |  |       # collected into an array of hashes. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @param url [String] the URL to fetch | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |       # @param options [Options] options to modify behavior | 
					
						
							| 
									
										
										
										
											2021-08-10 18:38:21 -04:00
										 |  |  |       # @return [Array] | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |       sig { params(url: String, options: Options).returns(T::Array[T::Hash[String, String]]) } | 
					
						
							|  |  |  |       def self.page_headers(url, options: Options.new) | 
					
						
							| 
									
										
										
										
											2020-12-19 00:46:18 -05:00
										 |  |  |         headers = [] | 
					
						
							| 
									
										
										
										
											2020-12-13 12:21:59 +01: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 options.post_form || options.post_json | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |           curl_post_args = ["--request", "POST", *post_args( | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |             post_form: options.post_form, | 
					
						
							|  |  |  |             post_json: options.post_json, | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |           )] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 02:10:38 +01:00
										 |  |  |         [:default, :browser].each do |user_agent| | 
					
						
							| 
									
										
										
										
											2023-05-09 07:25:00 +02:00
										 |  |  |           begin | 
					
						
							|  |  |  |             parsed_output = curl_headers( | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |               *curl_post_args, | 
					
						
							| 
									
										
										
										
											2023-05-15 13:14:13 -04:00
										 |  |  |               "--max-redirs", | 
					
						
							|  |  |  |               MAX_REDIRECTIONS.to_s, | 
					
						
							| 
									
										
										
										
											2023-05-09 07:25:00 +02:00
										 |  |  |               url, | 
					
						
							|  |  |  |               wanted_headers:    ["location", "content-disposition"], | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |               use_homebrew_curl: options.homebrew_curl || false, | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |               user_agent:, | 
					
						
							| 
									
										
										
										
											2023-05-09 07:25:00 +02:00
										 |  |  |               **DEFAULT_CURL_OPTIONS, | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           rescue ErrorDuringExecution | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-12-14 02:10:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 16:35:21 -04:00
										 |  |  |           parsed_output[:responses].each { |response| headers << response[:headers] } | 
					
						
							|  |  |  |           break if headers.present? | 
					
						
							| 
									
										
										
										
											2020-12-13 12:21:59 +01:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 02:10:38 +01:00
										 |  |  |         headers | 
					
						
							| 
									
										
										
										
											2020-12-12 21:56:07 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 22:46:52 -05:00
										 |  |  |       # Fetches the content at the URL and returns a hash containing the | 
					
						
							|  |  |  |       # content and, if there are any redirections, the final URL. | 
					
						
							| 
									
										
										
										
											2020-12-14 13:03:10 -05:00
										 |  |  |       # If `curl` encounters an error, the hash will contain a `:messages` | 
					
						
							|  |  |  |       # array with the error message instead. | 
					
						
							| 
									
										
										
										
											2020-12-22 22:46:52 -05:00
										 |  |  |       # | 
					
						
							|  |  |  |       # @param url [String] the URL of the content to check | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |       # @param options [Options] options to modify behavior | 
					
						
							| 
									
										
										
										
											2020-12-22 22:46:52 -05:00
										 |  |  |       # @return [Hash] | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |       sig { params(url: String, options: Options).returns(T::Hash[Symbol, T.untyped]) } | 
					
						
							|  |  |  |       def self.page_content(url, options: Options.new) | 
					
						
							|  |  |  |         if options.post_form || options.post_json | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |           curl_post_args = ["--request", "POST", *post_args( | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |             post_form: options.post_form, | 
					
						
							|  |  |  |             post_json: options.post_json, | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |           )] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-01 18:56:42 -07:00
										 |  |  |         stderr = T.let(nil, T.nilable(String)) | 
					
						
							| 
									
										
										
										
											2021-06-09 23:54:56 +02:00
										 |  |  |         [:default, :browser].each do |user_agent| | 
					
						
							| 
									
										
										
										
											2023-05-02 23:58:51 +02:00
										 |  |  |           stdout, stderr, status = curl_output( | 
					
						
							| 
									
										
										
										
											2025-02-04 10:30:16 -05:00
										 |  |  |             *curl_post_args, | 
					
						
							| 
									
										
										
										
											2021-06-09 23:54:56 +02:00
										 |  |  |             *PAGE_CONTENT_CURL_ARGS, url, | 
					
						
							|  |  |  |             **DEFAULT_CURL_OPTIONS, | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |             use_homebrew_curl: options.homebrew_curl || | 
					
						
							|  |  |  |                                !curl_supports_fail_with_body? || | 
					
						
							|  |  |  |                                false, | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |             user_agent: | 
					
						
							| 
									
										
										
										
											2021-06-09 23:54:56 +02:00
										 |  |  |           ) | 
					
						
							|  |  |  |           next unless status.success? | 
					
						
							| 
									
										
										
										
											2020-12-14 13:03:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 23:54:56 +02:00
										 |  |  |           # stdout contains the header information followed by the page content. | 
					
						
							|  |  |  |           # We use #scrub here to avoid "invalid byte sequence in UTF-8" errors. | 
					
						
							|  |  |  |           output = stdout.scrub | 
					
						
							| 
									
										
										
										
											2020-12-14 13:03:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 23:54:56 +02:00
										 |  |  |           # Separate the head(s)/body and identify the final URL (after any | 
					
						
							|  |  |  |           # redirections) | 
					
						
							| 
									
										
										
										
											2022-04-22 13:02:13 -04:00
										 |  |  |           parsed_output = parse_curl_output(output, max_iterations: MAX_PARSE_ITERATIONS) | 
					
						
							| 
									
										
										
										
											2021-05-04 16:35:21 -04:00
										 |  |  |           final_url = curl_response_last_location(parsed_output[:responses], absolutize: true, base_url: url) | 
					
						
							| 
									
										
										
										
											2020-12-14 13:03:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 16:35:21 -04:00
										 |  |  |           data = { content: parsed_output[:body] } | 
					
						
							|  |  |  |           data[:final_url] = final_url if final_url.present? && final_url != url | 
					
						
							| 
									
										
										
										
											2021-06-09 23:54:56 +02:00
										 |  |  |           return data | 
					
						
							| 
									
										
										
										
											2020-12-14 13:03:10 -05:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 11:58:28 -04:00
										 |  |  |         error_msgs = stderr&.scan(/^curl:.+$/) | 
					
						
							|  |  |  |         { messages: error_msgs.presence || ["cURL failed without a detectable error"] } | 
					
						
							| 
									
										
										
										
											2020-12-12 21:56:07 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-08-10 11:09:55 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # Handles the return value from a `strategy` block in a `livecheck` | 
					
						
							|  |  |  |       # block. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @param value [] the return value from a `strategy` block | 
					
						
							|  |  |  |       # @return [Array] | 
					
						
							|  |  |  |       sig { params(value: T.untyped).returns(T::Array[String]) } | 
					
						
							|  |  |  |       def self.handle_block_return(value) | 
					
						
							|  |  |  |         case value | 
					
						
							|  |  |  |         when String | 
					
						
							|  |  |  |           [value] | 
					
						
							|  |  |  |         when Array | 
					
						
							|  |  |  |           value.compact.uniq | 
					
						
							|  |  |  |         when nil | 
					
						
							|  |  |  |           [] | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           raise TypeError, INVALID_BLOCK_RETURN_VALUE_MSG | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require_relative "strategy/apache" | 
					
						
							|  |  |  | require_relative "strategy/bitbucket" | 
					
						
							| 
									
										
										
										
											2020-12-11 04:31:14 +01:00
										 |  |  | require_relative "strategy/cpan" | 
					
						
							| 
									
										
										
										
											2024-02-08 09:59:21 -05:00
										 |  |  | require_relative "strategy/crate" | 
					
						
							| 
									
										
										
										
											2021-03-17 01:58:31 +05:30
										 |  |  | require_relative "strategy/electron_builder" | 
					
						
							| 
									
										
										
										
											2021-04-04 03:00:34 +02:00
										 |  |  | require_relative "strategy/extract_plist" | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | require_relative "strategy/git" | 
					
						
							| 
									
										
										
										
											2020-12-02 18:04:22 +05:30
										 |  |  | require_relative "strategy/github_latest" | 
					
						
							| 
									
										
										
										
											2023-05-16 14:22:10 -04:00
										 |  |  | require_relative "strategy/github_releases" | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | require_relative "strategy/gnome" | 
					
						
							|  |  |  | require_relative "strategy/gnu" | 
					
						
							|  |  |  | require_relative "strategy/hackage" | 
					
						
							| 
									
										
										
										
											2020-12-14 02:49:32 +01:00
										 |  |  | require_relative "strategy/header_match" | 
					
						
							| 
									
										
										
										
											2023-02-23 12:40:07 -05:00
										 |  |  | require_relative "strategy/json" | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | require_relative "strategy/launchpad" | 
					
						
							|  |  |  | require_relative "strategy/npm" | 
					
						
							|  |  |  | require_relative "strategy/page_match" | 
					
						
							|  |  |  | require_relative "strategy/pypi" | 
					
						
							|  |  |  | require_relative "strategy/sourceforge" | 
					
						
							| 
									
										
										
										
											2020-12-12 21:59:04 +01:00
										 |  |  | require_relative "strategy/sparkle" | 
					
						
							| 
									
										
										
										
											2023-02-27 17:03:32 -05:00
										 |  |  | require_relative "strategy/xml" | 
					
						
							| 
									
										
										
										
											2020-08-08 07:16:06 +05:30
										 |  |  | require_relative "strategy/xorg" | 
					
						
							| 
									
										
										
										
											2023-03-02 15:19:00 -05:00
										 |  |  | require_relative "strategy/yaml" |