From c24af82a25f9ce625a81dbe19a93b0242989ae11 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 12 Dec 2020 21:59:04 +0100 Subject: [PATCH] Add `Sparkle` livecheck strategy. --- Library/Homebrew/livecheck/strategy.rb | 1 + .../Homebrew/livecheck/strategy/sparkle.rb | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Library/Homebrew/livecheck/strategy/sparkle.rb diff --git a/Library/Homebrew/livecheck/strategy.rb b/Library/Homebrew/livecheck/strategy.rb index 158fede7bd..1fa154a96d 100644 --- a/Library/Homebrew/livecheck/strategy.rb +++ b/Library/Homebrew/livecheck/strategy.rb @@ -112,4 +112,5 @@ require_relative "strategy/page_match" require_relative "strategy/pypi" require_relative "strategy/follow_redirection" require_relative "strategy/sourceforge" +require_relative "strategy/sparkle" require_relative "strategy/xorg" diff --git a/Library/Homebrew/livecheck/strategy/sparkle.rb b/Library/Homebrew/livecheck/strategy/sparkle.rb new file mode 100644 index 0000000000..5c3015defd --- /dev/null +++ b/Library/Homebrew/livecheck/strategy/sparkle.rb @@ -0,0 +1,56 @@ +# typed: false +# frozen_string_literal: true + +require_relative "page_match" + +module Homebrew + module Livecheck + module Strategy + # The {Sparkle} strategy fetches content at a URL and parses + # its contents as a Sparkle appcast in XML format. + # + # @api private + class Sparkle + extend T::Sig + + NICE_NAME = "Sparkle" + + PRIORITY = 1 + + # Whether the strategy can be applied to the provided URL. + sig { params(url: String).returns(T::Boolean) } + def self.match?(url) + url.match?(%r{^https?://}) && + ["application/xml", "text/xml"].include?(Strategy.page_headers(url)["content-type"]) && + Strategy.page_contents(url).include?("http://www.andymatuschak.org/xml-namespaces/sparkle") + end + + # Checks the content at the URL for new versions. + sig { params(url: String, regex: T.nilable(Regexp)).returns(T::Hash[Symbol, T.untyped]) } + def self.find_versions(url, regex) + raise ArgumentError, "The #{NICE_NAME} strategy does not support regular expressions." if regex + + require "nokogiri" + + match_data = { matches: {}, regex: regex, url: url } + + contents = Strategy.page_contents(url) + + xml = Nokogiri.parse(contents) + xml.remove_namespaces! + + match = xml.xpath("//rss//channel//item//enclosure") + .map { |enclosure| [*enclosure["shortVersionString"], *enclosure["version"]].uniq } + .reject(&:empty?) + .uniq + .max_by { |versions| versions.map { |v| Version.new(v) } } + &.join(",") + + match_data[:matches][match] = Version.new(match) if match + + match_data + end + end + end + end +end