102 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # 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
 | |
|     include Comparable
 | |
| 
 | |
|     extend SystemCommand::Mixin
 | |
| 
 | |
|     sig { params(info_plist_path: Pathname).returns(T.nilable(T.attached_class)) }
 | |
|     def self.from_info_plist(info_plist_path)
 | |
|       plist = system_command!("plutil", args: ["-convert", "xml1", "-o", "-", info_plist_path]).plist
 | |
|       from_info_plist_content(plist)
 | |
|     end
 | |
| 
 | |
|     sig { params(plist: T::Hash[String, T.untyped]).returns(T.nilable(T.attached_class)) }
 | |
|     def self.from_info_plist_content(plist)
 | |
|       short_version = plist["CFBundleShortVersionString"].presence
 | |
|       version = plist["CFBundleVersion"].presence
 | |
| 
 | |
|       new(short_version, version) if short_version || version
 | |
|     end
 | |
| 
 | |
|     sig { params(package_info_path: Pathname).returns(T.nilable(T.attached_class)) }
 | |
|     def self.from_package_info(package_info_path)
 | |
|       require "rexml/document"
 | |
| 
 | |
|       xml = REXML::Document.new(package_info_path.read)
 | |
| 
 | |
|       bundle_version_bundle = xml.get_elements("//pkg-info//bundle-version//bundle").first
 | |
|       bundle_id = bundle_version_bundle["id"] if bundle_version_bundle
 | |
|       return if bundle_id.blank?
 | |
| 
 | |
|       bundle = xml.get_elements("//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)
 | |
|       [version, short_version].map { |v| v&.yield_self(&Version.public_method(:new)) || Version::NULL } <=>
 | |
|         [other.version, other.short_version].map { |v| v&.yield_self(&Version.public_method(:new)) || Version::NULL }
 | |
|     end
 | |
| 
 | |
|     def ==(other)
 | |
|       instance_of?(other.class) && short_version == other.short_version && version == other.version
 | |
|     end
 | |
|     alias eql? ==
 | |
| 
 | |
|     # Create a nicely formatted version (on a best effort basis).
 | |
|     sig { returns(String) }
 | |
|     def nice_version
 | |
|       nice_parts.join(",")
 | |
|     end
 | |
| 
 | |
|     sig { returns(T::Array[String]) }
 | |
|     def nice_parts
 | |
|       short_version = self.short_version
 | |
|       version = self.version
 | |
| 
 | |
|       short_version = short_version&.delete_suffix("(#{version})") if version
 | |
| 
 | |
|       return [T.must(short_version)] if short_version == version
 | |
| 
 | |
|       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
 | |
| 
 | |
|       [short_version, version].compact
 | |
|     end
 | |
|     private :nice_parts
 | |
|   end
 | |
| end
 | 
