Allow regex to be passed into all strategy blocks
This modifies cask-related livecheck strategies to allow passing a regex into a `strategy` block, when appropriate. These strategies were outliers that explicitly rejected a regex even if a `strategy` block was used, forcing any regex to be inlined in the `strategy` block (instead of being defined using `#regex`). With these changes, all `strategy` blocks will be able to accept a regex, further simplifying the mental model. This also helps to better align the various `find_versions` and `versions_from_*` methods across strategies.
This commit is contained in:
parent
27a76295a4
commit
9e8900fb6e
@ -39,18 +39,22 @@ module Homebrew
|
|||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
content: String,
|
content: String,
|
||||||
|
regex: T.nilable(Regexp),
|
||||||
block: T.nilable(
|
block: T.nilable(
|
||||||
T.proc.params(arg0: T::Hash[String, T.untyped]).returns(T.any(String, T::Array[String], NilClass)),
|
T.proc.params(
|
||||||
|
arg0: T::Hash[String, T.untyped],
|
||||||
|
arg1: T.nilable(Regexp),
|
||||||
|
).returns(T.any(String, T::Array[String], NilClass)),
|
||||||
),
|
),
|
||||||
).returns(T::Array[String])
|
).returns(T::Array[String])
|
||||||
}
|
}
|
||||||
def self.versions_from_content(content, &block)
|
def self.versions_from_content(content, regex = nil, &block)
|
||||||
require "yaml"
|
require "yaml"
|
||||||
|
|
||||||
yaml = YAML.safe_load(content)
|
yaml = YAML.safe_load(content)
|
||||||
return [] if yaml.blank?
|
return [] if yaml.blank?
|
||||||
|
|
||||||
return Strategy.handle_block_return(yield(yaml)) if block
|
return Strategy.handle_block_return(yield(yaml, regex)) if block
|
||||||
|
|
||||||
version = yaml["version"]
|
version = yaml["version"]
|
||||||
version.present? ? [version] : []
|
version.present? ? [version] : []
|
||||||
@ -62,20 +66,28 @@ module Homebrew
|
|||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
url: String,
|
url: String,
|
||||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
regex: T.nilable(Regexp),
|
||||||
block: T.nilable(T.proc.params(arg0: T::Hash[String, T.untyped]).returns(T.nilable(String))),
|
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||||
|
block: T.nilable(
|
||||||
|
T.proc.params(
|
||||||
|
arg0: T::Hash[String, T.untyped],
|
||||||
|
arg1: T.nilable(Regexp),
|
||||||
|
).returns(T.any(String, T::Array[String], NilClass)),
|
||||||
|
),
|
||||||
).returns(T::Hash[Symbol, T.untyped])
|
).returns(T::Hash[Symbol, T.untyped])
|
||||||
}
|
}
|
||||||
def self.find_versions(url:, **unused, &block)
|
def self.find_versions(url:, regex: nil, **_unused, &block)
|
||||||
raise ArgumentError, "The #{T.must(name).demodulize} strategy does not support a regex." if unused[:regex]
|
if regex.present? && block.blank?
|
||||||
|
raise ArgumentError, "#{T.must(name).demodulize} only supports a regex when using a `strategy` block"
|
||||||
|
end
|
||||||
|
|
||||||
match_data = { matches: {}, url: url }
|
match_data = { matches: {}, url: url }
|
||||||
|
|
||||||
match_data.merge!(Strategy.page_content(url))
|
match_data.merge!(Strategy.page_content(url))
|
||||||
content = match_data.delete(:content)
|
content = match_data.delete(:content)
|
||||||
|
|
||||||
versions_from_content(content, &block).each do |version_text|
|
versions_from_content(content, regex, &block).each do |version_text|
|
||||||
match_data[:matches][version_text] = Version.new(version_text)
|
match_data[:matches][version_text] = Version.new(version_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -62,13 +62,17 @@ module Homebrew
|
|||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
items: T::Hash[String, Item],
|
items: T::Hash[String, Item],
|
||||||
|
regex: T.nilable(Regexp),
|
||||||
block: T.nilable(
|
block: T.nilable(
|
||||||
T.proc.params(arg0: T::Hash[String, Item]).returns(T.any(String, T::Array[String], NilClass)),
|
T.proc.params(
|
||||||
|
arg0: T::Hash[String, Item],
|
||||||
|
arg1: T.nilable(Regexp),
|
||||||
|
).returns(T.any(String, T::Array[String], NilClass)),
|
||||||
),
|
),
|
||||||
).returns(T::Array[String])
|
).returns(T::Array[String])
|
||||||
}
|
}
|
||||||
def self.versions_from_items(items, &block)
|
def self.versions_from_items(items, regex = nil, &block)
|
||||||
return Strategy.handle_block_return(yield(items)) if block
|
return Strategy.handle_block_return(yield(items, regex)) if block
|
||||||
|
|
||||||
items.map do |_key, item|
|
items.map do |_key, item|
|
||||||
item.bundle_version.nice_version
|
item.bundle_version.nice_version
|
||||||
@ -82,15 +86,21 @@ module Homebrew
|
|||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
cask: Cask::Cask,
|
cask: Cask::Cask,
|
||||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
regex: T.nilable(Regexp),
|
||||||
block: T.nilable(
|
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||||
T.proc.params(arg0: T::Hash[String, Item]).returns(T.any(String, T::Array[String], NilClass)),
|
block: T.nilable(
|
||||||
|
T.proc.params(
|
||||||
|
arg0: T::Hash[String, Item],
|
||||||
|
arg1: T.nilable(Regexp),
|
||||||
|
).returns(T.any(String, T::Array[String], NilClass)),
|
||||||
),
|
),
|
||||||
).returns(T::Hash[Symbol, T.untyped])
|
).returns(T::Hash[Symbol, T.untyped])
|
||||||
}
|
}
|
||||||
def self.find_versions(cask:, **unused, &block)
|
def self.find_versions(cask:, regex: nil, **_unused, &block)
|
||||||
raise ArgumentError, "The #{T.must(name).demodulize} strategy does not support a regex." if unused[:regex]
|
if regex.present? && block.blank?
|
||||||
|
raise ArgumentError, "#{T.must(name).demodulize} only supports a regex when using a `strategy` block"
|
||||||
|
end
|
||||||
raise ArgumentError, "The #{T.must(name).demodulize} strategy only supports casks." unless T.unsafe(cask)
|
raise ArgumentError, "The #{T.must(name).demodulize} strategy only supports casks." unless T.unsafe(cask)
|
||||||
|
|
||||||
match_data = { matches: {} }
|
match_data = { matches: {} }
|
||||||
@ -98,7 +108,7 @@ module Homebrew
|
|||||||
unversioned_cask_checker = UnversionedCaskChecker.new(cask)
|
unversioned_cask_checker = UnversionedCaskChecker.new(cask)
|
||||||
items = unversioned_cask_checker.all_versions.transform_values { |v| Item.new(bundle_version: v) }
|
items = unversioned_cask_checker.all_versions.transform_values { |v| Item.new(bundle_version: v) }
|
||||||
|
|
||||||
versions_from_items(items, &block).each do |version_text|
|
versions_from_items(items, regex, &block).each do |version_text|
|
||||||
match_data[:matches][version_text] = Version.new(version_text)
|
match_data[:matches][version_text] = Version.new(version_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -150,14 +150,17 @@ module Homebrew
|
|||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
content: String,
|
content: String,
|
||||||
block: T.nilable(T.proc.params(arg0: Item).returns(T.any(String, T::Array[String], NilClass))),
|
regex: T.nilable(Regexp),
|
||||||
|
block: T.nilable(
|
||||||
|
T.proc.params(arg0: Item, arg1: T.nilable(Regexp)).returns(T.any(String, T::Array[String], NilClass)),
|
||||||
|
),
|
||||||
).returns(T::Array[String])
|
).returns(T::Array[String])
|
||||||
}
|
}
|
||||||
def self.versions_from_content(content, &block)
|
def self.versions_from_content(content, regex = nil, &block)
|
||||||
item = item_from_content(content)
|
item = item_from_content(content)
|
||||||
return [] if item.blank?
|
return [] if item.blank?
|
||||||
|
|
||||||
return Strategy.handle_block_return(yield(item)) if block
|
return Strategy.handle_block_return(yield(item, regex)) if block
|
||||||
|
|
||||||
version = item.bundle_version&.nice_version
|
version = item.bundle_version&.nice_version
|
||||||
version.present? ? [version] : []
|
version.present? ? [version] : []
|
||||||
@ -166,20 +169,25 @@ module Homebrew
|
|||||||
# Checks the content at the URL for new versions.
|
# Checks the content at the URL for new versions.
|
||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
url: String,
|
url: String,
|
||||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
regex: T.nilable(Regexp),
|
||||||
block: T.nilable(T.proc.params(arg0: Item).returns(T.nilable(String))),
|
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||||
|
block: T.nilable(
|
||||||
|
T.proc.params(arg0: Item, arg1: T.nilable(Regexp)).returns(T.any(String, T::Array[String], NilClass)),
|
||||||
|
),
|
||||||
).returns(T::Hash[Symbol, T.untyped])
|
).returns(T::Hash[Symbol, T.untyped])
|
||||||
}
|
}
|
||||||
def self.find_versions(url:, **unused, &block)
|
def self.find_versions(url:, regex: nil, **_unused, &block)
|
||||||
raise ArgumentError, "The #{T.must(name).demodulize} strategy does not support a regex." if unused[:regex]
|
if regex.present? && block.blank?
|
||||||
|
raise ArgumentError, "#{T.must(name).demodulize} only supports a regex when using a `strategy` block"
|
||||||
|
end
|
||||||
|
|
||||||
match_data = { matches: {}, url: url }
|
match_data = { matches: {}, url: url }
|
||||||
|
|
||||||
match_data.merge!(Strategy.page_content(url))
|
match_data.merge!(Strategy.page_content(url))
|
||||||
content = match_data.delete(:content)
|
content = match_data.delete(:content)
|
||||||
|
|
||||||
versions_from_content(content, &block).each do |version_text|
|
versions_from_content(content, regex, &block).each do |version_text|
|
||||||
match_data[:matches][version_text] = Version.new(version_text)
|
match_data[:matches][version_text] = Version.new(version_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ describe Homebrew::Livecheck::Strategy::ElectronBuilder do
|
|||||||
releaseDate: '2000-01-01T00:00:00.000Z'
|
releaseDate: '2000-01-01T00:00:00.000Z'
|
||||||
EOS
|
EOS
|
||||||
}
|
}
|
||||||
|
let(:mac_regex) { /Example[._-]v?(\d+(?:\.\d+)+)[._-]mac\.zip/i }
|
||||||
|
|
||||||
let(:versions) { ["1.2.3"] }
|
let(:versions) { ["1.2.3"] }
|
||||||
|
|
||||||
@ -59,6 +60,26 @@ describe Homebrew::Livecheck::Strategy::ElectronBuilder do
|
|||||||
expect(electron_builder.versions_from_content(electron_builder_yaml) { versions }).to eq(versions)
|
expect(electron_builder.versions_from_content(electron_builder_yaml) { versions }).to eq(versions)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns an array of version strings when given YAML text, a regex, and a block" do
|
||||||
|
# Returning a string from block
|
||||||
|
expect(
|
||||||
|
electron_builder.versions_from_content(electron_builder_yaml, mac_regex) do |yaml, regex|
|
||||||
|
yaml["path"][regex, 1]
|
||||||
|
end,
|
||||||
|
).to eq(versions)
|
||||||
|
|
||||||
|
# Returning an array of strings from block
|
||||||
|
expect(
|
||||||
|
electron_builder.versions_from_content(electron_builder_yaml, mac_regex) do |yaml, regex|
|
||||||
|
yaml["files"]&.map do |file|
|
||||||
|
next if file["url"].blank?
|
||||||
|
|
||||||
|
file["url"][regex, 1]
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
).to eq(versions)
|
||||||
|
end
|
||||||
|
|
||||||
it "allows a nil return from a block" do
|
it "allows a nil return from a block" do
|
||||||
expect(electron_builder.versions_from_content(electron_builder_yaml) { next }).to eq([])
|
expect(electron_builder.versions_from_content(electron_builder_yaml) { next }).to eq([])
|
||||||
end
|
end
|
||||||
|
@ -21,7 +21,20 @@ describe Homebrew::Livecheck::Strategy::ExtractPlist do
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:multipart_items) do
|
||||||
|
{
|
||||||
|
"first" => extract_plist::Item.new(
|
||||||
|
bundle_version: Homebrew::BundleVersion.new(nil, "1.2.3-45"),
|
||||||
|
),
|
||||||
|
"second" => extract_plist::Item.new(
|
||||||
|
bundle_version: Homebrew::BundleVersion.new(nil, "1.2.3-45-abcdef"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:multipart_regex) { /^v?(\d+(?:\.\d+)+)(?:[._-](\d+))?(?:[._-]([0-9a-f]+))?$/i }
|
||||||
|
|
||||||
let(:versions) { ["1.2", "1.2.3"] }
|
let(:versions) { ["1.2", "1.2.3"] }
|
||||||
|
let(:multipart_versions) { ["1.2.3,45", "1.2.3,45,abcdef"] }
|
||||||
|
|
||||||
describe "::match?" do
|
describe "::match?" do
|
||||||
it "returns true for an HTTP URL" do
|
it "returns true for an HTTP URL" do
|
||||||
@ -60,6 +73,30 @@ describe Homebrew::Livecheck::Strategy::ExtractPlist do
|
|||||||
).to eq(versions)
|
).to eq(versions)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns an array of version strings when given Items, a regex, and a block" do
|
||||||
|
# Returning a string from block
|
||||||
|
expect(
|
||||||
|
extract_plist.versions_from_items(multipart_items, multipart_regex) do |items, regex|
|
||||||
|
match = items["first"].version.match(regex)
|
||||||
|
next if match.blank?
|
||||||
|
|
||||||
|
match[1..].compact.join(",")
|
||||||
|
end,
|
||||||
|
).to eq(["1.2.3,45"])
|
||||||
|
|
||||||
|
# Returning an array of strings from block
|
||||||
|
expect(
|
||||||
|
extract_plist.versions_from_items(multipart_items, multipart_regex) do |items, regex|
|
||||||
|
items.map do |_key, item|
|
||||||
|
match = item.version.match(regex)
|
||||||
|
next if match.blank?
|
||||||
|
|
||||||
|
match[1..].compact.join(",")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
).to eq(multipart_versions)
|
||||||
|
end
|
||||||
|
|
||||||
it "allows a nil return from a block" do
|
it "allows a nil return from a block" do
|
||||||
expect(extract_plist.versions_from_items(items) { next }).to eq([])
|
expect(extract_plist.versions_from_items(items) { next }).to eq([])
|
||||||
end
|
end
|
||||||
|
@ -41,6 +41,8 @@ describe Homebrew::Livecheck::Strategy::Sparkle do
|
|||||||
EOS
|
EOS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let(:title_regex) { /Version\s+v?(\d+(?:\.\d+)+)\s*$/i }
|
||||||
|
|
||||||
let(:item) {
|
let(:item) {
|
||||||
Homebrew::Livecheck::Strategy::Sparkle::Item.new(
|
Homebrew::Livecheck::Strategy::Sparkle::Item.new(
|
||||||
title: appcast_data[:title],
|
title: appcast_data[:title],
|
||||||
@ -93,10 +95,26 @@ describe Homebrew::Livecheck::Strategy::Sparkle do
|
|||||||
end,
|
end,
|
||||||
).to eq([item.bundle_version.nice_version.sub("3", "4")])
|
).to eq([item.bundle_version.nice_version.sub("3", "4")])
|
||||||
|
|
||||||
# Returning an array of strings from block
|
# Returning an array of strings from block (unlikely to be used)
|
||||||
expect(sparkle.versions_from_content(appcast_xml) { versions }).to eq(versions)
|
expect(sparkle.versions_from_content(appcast_xml) { versions }).to eq(versions)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns an array of version strings when given content, a regex, and a block" do
|
||||||
|
# Returning a string from block
|
||||||
|
expect(
|
||||||
|
sparkle.versions_from_content(appcast_xml, title_regex) do |item, regex|
|
||||||
|
item.title[regex, 1]
|
||||||
|
end,
|
||||||
|
).to eq([item.bundle_version.short_version])
|
||||||
|
|
||||||
|
# Returning an array of strings from block (unlikely to be used)
|
||||||
|
expect(
|
||||||
|
sparkle.versions_from_content(appcast_xml, title_regex) do |item, regex|
|
||||||
|
[item.title[regex, 1]]
|
||||||
|
end,
|
||||||
|
).to eq([item.bundle_version.short_version])
|
||||||
|
end
|
||||||
|
|
||||||
it "allows a nil return from a block" do
|
it "allows a nil return from a block" do
|
||||||
expect(sparkle.versions_from_content(appcast_xml) { next }).to eq([])
|
expect(sparkle.versions_from_content(appcast_xml) { next }).to eq([])
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user