2020-12-13 12:19:15 +01:00
|
|
|
# typed: true
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require "system_command"
|
|
|
|
|
|
|
|
module Homebrew
|
|
|
|
# Representation of a macOS bundle version, commonly found in `Info.plist` files.
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
class BundleVersion
|
|
|
|
extend T::Sig
|
|
|
|
|
|
|
|
extend SystemCommand::Mixin
|
|
|
|
|
2020-12-15 15:21:14 +01:00
|
|
|
sig { params(info_plist_path: Pathname).returns(T.nilable(T.attached_class)) }
|
2020-12-13 12:19:15 +01:00
|
|
|
def self.from_info_plist(info_plist_path)
|
|
|
|
plist = system_command!("plutil", args: ["-convert", "xml1", "-o", "-", info_plist_path]).plist
|
|
|
|
|
|
|
|
short_version = plist["CFBundleShortVersionString"].presence
|
|
|
|
version = plist["CFBundleVersion"].presence
|
|
|
|
|
|
|
|
new(short_version, version) if short_version || version
|
|
|
|
end
|
|
|
|
|
2020-12-15 15:21:14 +01:00
|
|
|
sig { params(package_info_path: Pathname).returns(T.nilable(T.attached_class)) }
|
2020-12-13 12:19:15 +01:00
|
|
|
def self.from_package_info(package_info_path)
|
|
|
|
Homebrew.install_bundler_gems!
|
|
|
|
require "nokogiri"
|
|
|
|
|
|
|
|
xml = Nokogiri::XML(package_info_path.read)
|
|
|
|
|
|
|
|
bundle_id = xml.xpath("//pkg-info//bundle-version//bundle").first&.attr("id")
|
|
|
|
return unless bundle_id
|
|
|
|
|
|
|
|
bundle = xml.xpath("//pkg-info//bundle").find { |b| b["id"] == bundle_id }
|
|
|
|
return unless bundle
|
|
|
|
|
|
|
|
short_version = bundle["CFBundleShortVersionString"]
|
|
|
|
version = bundle["CFBundleVersion"]
|
|
|
|
|
|
|
|
new(short_version, version) if short_version || version
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(T.nilable(String)) }
|
|
|
|
attr_reader :short_version, :version
|
|
|
|
|
|
|
|
sig { params(short_version: T.nilable(String), version: T.nilable(String)).void }
|
|
|
|
def initialize(short_version, version)
|
|
|
|
@short_version = short_version.presence
|
|
|
|
@version = version.presence
|
|
|
|
|
|
|
|
return if @short_version || @version
|
|
|
|
|
|
|
|
raise ArgumentError, "`short_version` and `version` cannot both be `nil` or empty"
|
|
|
|
end
|
|
|
|
|
|
|
|
def <=>(other)
|
2020-12-14 02:09:58 +01:00
|
|
|
[version, short_version].map { |v| v&.yield_self(&Version.public_method(:new)) } <=>
|
|
|
|
[other.version, other.short_version].map { |v| v&.yield_self(&Version.public_method(:new)) }
|
2020-12-13 12:19:15 +01:00
|
|
|
end
|
|
|
|
|
2020-12-15 17:11:18 +01:00
|
|
|
# Create a nicely formatted version (on a best effort basis).
|
2020-12-13 12:19:15 +01:00
|
|
|
sig { returns(String) }
|
|
|
|
def nice_version
|
|
|
|
nice_parts.join(",")
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(T::Array[String]) }
|
|
|
|
def nice_parts
|
2020-12-14 11:47:57 +01:00
|
|
|
short_version = self.short_version
|
2020-12-15 15:21:14 +01:00
|
|
|
version = self.version
|
|
|
|
|
2020-12-14 11:47:57 +01:00
|
|
|
short_version = short_version&.delete_suffix("(#{version})") if version
|
2020-12-14 09:26:30 +01:00
|
|
|
|
2020-12-15 15:21:14 +01:00
|
|
|
return [T.must(short_version)] if short_version == version
|
2020-12-13 12:19:15 +01:00
|
|
|
|
|
|
|
if short_version && version
|
|
|
|
return [version] if version.match?(/\A\d+(\.\d+)+\Z/) && version.start_with?("#{short_version}.")
|
|
|
|
return [short_version] if short_version.match?(/\A\d+(\.\d+)+\Z/) && short_version.start_with?("#{version}.")
|
|
|
|
|
|
|
|
if short_version.match?(/\A\d+(\.\d+)*\Z/) && version.match?(/\A\d+\Z/)
|
|
|
|
return [short_version] if short_version.start_with?("#{version}.") || short_version.end_with?(".#{version}")
|
|
|
|
|
|
|
|
return [short_version, version]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-12-14 09:04:54 +01:00
|
|
|
[short_version, version].compact
|
2020-12-13 12:19:15 +01:00
|
|
|
end
|
|
|
|
private :nice_parts
|
|
|
|
end
|
|
|
|
end
|