122 lines
4.2 KiB
Ruby
Raw Normal View History

2020-12-24 03:33:14 +01:00
# typed: true
# frozen_string_literal: true
module Homebrew
module Livecheck
module Strategy
# The {PageMatch} strategy fetches content at a URL and scans it for
# matching text using the provided regex.
#
# This strategy can be used in a `livecheck` block when no specific
# strategies apply to a given URL. Though {PageMatch} will technically
# match any HTTP URL, the strategy also requires a regex to function.
#
# The {find_versions} method is also used within other
# strategies, to handle the process of identifying version text in
# content.
#
# @api public
class PageMatch
2020-12-24 03:33:14 +01:00
extend T::Sig
NICE_NAME = "Page match"
# A priority of zero causes livecheck to skip the strategy. We do this
# for PageMatch so we can selectively apply the strategy only when a
# regex is provided in a `livecheck` block.
PRIORITY = 0
# The `Regexp` used to determine if the strategy applies to the URL.
URL_MATCH_REGEX = %r{^https?://}i.freeze
# Whether the strategy can be applied to the provided URL.
# PageMatch will technically match any HTTP URL but is only
# usable with a `livecheck` block containing a regex.
2020-12-24 03:33:14 +01:00
sig { params(url: String).returns(T::Boolean) }
def self.match?(url)
URL_MATCH_REGEX.match?(url)
end
2020-12-22 22:46:52 -05:00
# Uses the regex to match text in the content or, if a block is
# provided, passes the page content to the block to handle matching.
# With either approach, an array of unique matches is returned.
#
2020-12-22 22:46:52 -05:00
# @param content [String] the page content to check
# @param regex [Regexp] a regex used for matching versions in the
# content
# @return [Array]
sig {
params(
content: String,
regex: Regexp,
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Array[String])
}
2020-12-22 22:46:52 -05:00
def self.page_matches(content, regex, &block)
2020-12-14 02:07:07 +01:00
if block
case (value = block.call(content, regex))
2020-12-14 02:07:07 +01:00
when String
return [value]
when Array
return value.compact.uniq
when nil
return []
2020-12-14 02:07:07 +01:00
else
2020-12-14 02:16:01 +01:00
raise TypeError, "Return value of `strategy :page_match` block must be a string or array of strings."
2020-12-14 02:07:07 +01:00
end
end
2020-12-14 02:07:07 +01:00
2020-12-22 22:46:52 -05:00
content.scan(regex).map do |match|
2020-12-15 20:08:53 +01:00
case match
when String
match
when Array
2020-12-15 20:08:53 +01:00
match.first
end
end.compact.uniq
end
# Checks the content at the URL for new versions, using the provided
# regex for matching.
2020-12-23 09:12:53 -05:00
#
# @param url [String] the URL of the content to check
# @param regex [Regexp] a regex used for matching versions in content
# @param provided_content [String] page content to use in place of
# fetching via Strategy#page_content
# @return [Hash]
sig {
2020-12-23 09:12:53 -05:00
params(
url: String,
regex: Regexp,
2021-04-04 03:00:34 +02:00
cask: T.nilable(Cask::Cask),
2020-12-23 09:12:53 -05:00
provided_content: T.nilable(String),
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
2020-12-23 09:12:53 -05:00
).returns(T::Hash[Symbol, T.untyped])
}
2021-04-04 03:00:34 +02:00
def self.find_versions(url, regex, cask: nil, provided_content: nil, &block)
match_data = { matches: {}, regex: regex, url: url }
content = if provided_content.is_a?(String)
match_data[:cached] = true
2020-12-23 09:12:53 -05:00
provided_content
else
match_data.merge!(Strategy.page_content(url))
match_data[:content]
2020-12-23 09:12:53 -05:00
end
2020-12-22 22:46:52 -05:00
return match_data if content.blank?
page_matches(content, regex, &block).each do |match_text|
match_data[:matches][match_text] = Version.new(match_text)
end
match_data
end
end
end
end
end