Merge HeadVersion
and NullVersion
into Version
.
This commit is contained in:
parent
b05de929c6
commit
a1efaf1864
@ -7,10 +7,10 @@ module Language
|
||||
# @api public
|
||||
module Python
|
||||
def self.major_minor_version(python)
|
||||
version = /\d\.\d+/.match `#{python} --version 2>&1`
|
||||
version = `#{python} --version 2>&1`.chomp[/(\d\.\d+)/, 1]
|
||||
return unless version
|
||||
|
||||
Version.create(version.to_s)
|
||||
Version.new(version)
|
||||
end
|
||||
|
||||
def self.homebrew_site_packages(python = "python3.7")
|
||||
|
@ -1,6 +1,7 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "os/mac/version"
|
||||
require "utils"
|
||||
|
||||
module OS
|
||||
@ -53,11 +54,11 @@ module OS
|
||||
raise "Loaded OS::Linux on generic OS!" if ENV["HOMEBREW_TEST_GENERIC_OS"]
|
||||
|
||||
def self.version
|
||||
::Version::NULL
|
||||
Version::NULL
|
||||
end
|
||||
|
||||
def self.full_version
|
||||
::Version::NULL
|
||||
Version::NULL
|
||||
end
|
||||
|
||||
def self.languages
|
||||
|
@ -30,18 +30,29 @@ module OS
|
||||
|
||||
sig { override.params(other: T.untyped).returns(T.nilable(Integer)) }
|
||||
def <=>(other)
|
||||
@comparison_cache.fetch(other) do
|
||||
return @comparison_cache[other] if @comparison_cache.key?(other)
|
||||
|
||||
result = case other
|
||||
when Symbol
|
||||
if MacOSVersions::SYMBOLS.key?(other) && to_sym == other
|
||||
0
|
||||
else
|
||||
v = MacOSVersions::SYMBOLS.fetch(other) { other.to_s }
|
||||
@comparison_cache[other] = super(::Version.new(v))
|
||||
super(v)
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
|
||||
@comparison_cache[other] = result unless frozen?
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
sig { returns(T.self_type) }
|
||||
def strip_patch
|
||||
return self if null?
|
||||
|
||||
# Big Sur is 11.x but Catalina is 10.15.x.
|
||||
if T.must(major) >= 11
|
||||
self.class.new(major.to_s)
|
||||
@ -52,12 +63,24 @@ module OS
|
||||
|
||||
sig { returns(Symbol) }
|
||||
def to_sym
|
||||
@to_sym ||= MacOSVersions::SYMBOLS.invert.fetch(strip_patch.to_s, :dunno)
|
||||
return @sym if defined?(@sym)
|
||||
|
||||
sym = MacOSVersions::SYMBOLS.invert.fetch(strip_patch.to_s, :dunno)
|
||||
|
||||
@sym = sym unless frozen?
|
||||
|
||||
sym
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def pretty_name
|
||||
@pretty_name ||= to_sym.to_s.split("_").map(&:capitalize).join(" ").freeze
|
||||
return @pretty_name if defined?(@pretty_name)
|
||||
|
||||
pretty_name = to_sym.to_s.split("_").map(&:capitalize).join(" ").freeze
|
||||
|
||||
@pretty_name = pretty_name unless frozen?
|
||||
|
||||
pretty_name
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
@ -78,6 +101,8 @@ module OS
|
||||
# For {OS::Mac::Version} compatibility.
|
||||
sig { returns(T::Boolean) }
|
||||
def requires_nehalem_cpu?
|
||||
return false if null?
|
||||
|
||||
unless Hardware::CPU.intel?
|
||||
raise "Unexpected architecture: #{Hardware::CPU.arch}. This only works with Intel architecture."
|
||||
end
|
||||
@ -90,6 +115,9 @@ module OS
|
||||
alias requires_sse41? requires_nehalem_cpu?
|
||||
alias requires_sse42? requires_nehalem_cpu?
|
||||
alias requires_popcnt? requires_nehalem_cpu?
|
||||
|
||||
# Represents the absence of a version.
|
||||
NULL = Version.new("10.0").tap { |v| v.instance_variable_set(:@version, nil) }.freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -190,6 +190,7 @@ class Resource < Downloadable
|
||||
@download_strategy = @url.download_strategy
|
||||
end
|
||||
|
||||
sig { params(val: T.nilable(T.any(String, Version))).returns(T.nilable(Version)) }
|
||||
def version(val = nil)
|
||||
return super() if val.nil?
|
||||
|
||||
|
@ -315,11 +315,11 @@ class Tab
|
||||
end
|
||||
|
||||
def stable_version
|
||||
Version.create(versions["stable"]) if versions["stable"]
|
||||
versions["stable"]&.then(&Version.method(:new))
|
||||
end
|
||||
|
||||
def head_version
|
||||
Version.create(versions["head"]) if versions["head"]
|
||||
versions["head"]&.then(&Version.method(:new))
|
||||
end
|
||||
|
||||
def version_scheme
|
||||
|
@ -15,16 +15,11 @@ describe OS::Mac::Version do
|
||||
expect(version).to be < :catalina
|
||||
end
|
||||
|
||||
specify "comparison with Fixnum" do
|
||||
specify "comparison with Integer" do
|
||||
expect(version).to be > 10
|
||||
expect(version).to be < 11
|
||||
end
|
||||
|
||||
specify "comparison with Float" do
|
||||
expect(version).to be > 10.13
|
||||
expect(version).to be < 10.15
|
||||
end
|
||||
|
||||
specify "comparison with String" do
|
||||
expect(version).to be > "10.3"
|
||||
expect(version).to be == "10.14"
|
||||
|
@ -2,8 +2,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "pkg_version"
|
||||
require "version/head"
|
||||
require "version/null"
|
||||
require "version/parser"
|
||||
|
||||
# A formula's version.
|
||||
@ -343,37 +341,25 @@ class Version
|
||||
parse(specs.fetch(:tag, url), detected_from_url: true)
|
||||
end
|
||||
|
||||
# TODO: `odeprecate` this and just use `Version.new`.
|
||||
sig { params(val: String).returns(Version) }
|
||||
def self.create(val)
|
||||
raise TypeError, "Version value must be a string; got a #{val.class} (#{val})" unless val.respond_to?(:to_str)
|
||||
|
||||
if val.to_str.start_with?("HEAD")
|
||||
HeadVersion.new(val)
|
||||
else
|
||||
Version.new(val)
|
||||
end
|
||||
new(val)
|
||||
end
|
||||
|
||||
sig { params(spec: T.any(String, Pathname), detected_from_url: T::Boolean).returns(Version) }
|
||||
sig { params(spec: T.any(String, Pathname), detected_from_url: T::Boolean).returns(T.attached_class) }
|
||||
def self.parse(spec, detected_from_url: false)
|
||||
version = _parse(spec, detected_from_url: detected_from_url)
|
||||
version.nil? ? NULL : new(version, detected_from_url: detected_from_url)
|
||||
end
|
||||
|
||||
sig { params(spec: T.any(String, Pathname), detected_from_url: T::Boolean).returns(T.nilable(String)) }
|
||||
def self._parse(spec, detected_from_url:)
|
||||
spec = CGI.unescape(spec.to_s) if detected_from_url
|
||||
|
||||
spec = Pathname.new(spec) unless spec.is_a? Pathname
|
||||
spec = Pathname(spec)
|
||||
|
||||
VERSION_PARSERS.each do |parser|
|
||||
version = parser.parse(spec)
|
||||
return version if version.present?
|
||||
return new(version, detected_from_url: detected_from_url) if version.present?
|
||||
end
|
||||
|
||||
nil
|
||||
NULL
|
||||
end
|
||||
private_class_method :_parse
|
||||
|
||||
NUMERIC_WITH_OPTIONAL_DOTS = /(?:\d+(?:\.\d+)*)/.source.freeze
|
||||
private_constant :NUMERIC_WITH_OPTIONAL_DOTS
|
||||
@ -517,14 +503,36 @@ class Version
|
||||
@detected_from_url
|
||||
end
|
||||
|
||||
HEAD_VERSION_REGEX = /\AHEAD(?:-(?<commit>.*))?\Z/.freeze
|
||||
private_constant :HEAD_VERSION_REGEX
|
||||
|
||||
# Check if this is a HEAD version.
|
||||
sig { returns(T::Boolean) }
|
||||
def head?
|
||||
false
|
||||
version&.match?(HEAD_VERSION_REGEX) || false
|
||||
end
|
||||
|
||||
# Return the commit for a HEAD version.
|
||||
sig { returns(T.nilable(String)) }
|
||||
def commit
|
||||
version&.match(HEAD_VERSION_REGEX)&.[](:commit)
|
||||
end
|
||||
|
||||
# Update the commit for a HEAD version.
|
||||
sig { params(commit: T.nilable(String)).void }
|
||||
def update_commit(commit)
|
||||
raise ArgumentError, "Cannot update commit for non-HEAD version." unless head?
|
||||
|
||||
@version = if commit
|
||||
"HEAD-#{commit}"
|
||||
else
|
||||
"HEAD"
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def null?
|
||||
false
|
||||
@version.nil?
|
||||
end
|
||||
|
||||
sig { params(comparator: String, other: Version).returns(T::Boolean) }
|
||||
@ -542,16 +550,47 @@ class Version
|
||||
|
||||
sig { params(other: T.untyped).returns(T.nilable(Integer)) }
|
||||
def <=>(other)
|
||||
# Needed to retain API compatibility with older string comparisons
|
||||
# for compiler versions, etc.
|
||||
other = Version.new(other) if other.is_a? String
|
||||
# Used by the *_build_version comparisons, which formerly returned Fixnum
|
||||
other = Version.new(other.to_s) if other.is_a? Integer
|
||||
return 1 if other.nil?
|
||||
return 1 if other.respond_to?(:null?) && other.null?
|
||||
other = case other
|
||||
when String
|
||||
if other.blank?
|
||||
# Cannot compare `NULL` to empty string.
|
||||
return if null?
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
# Needed to retain API compatibility with older string comparisons for compiler versions, etc.
|
||||
Version.new(other)
|
||||
when Integer
|
||||
# Used by the `*_build_version` comparisons, which formerly returned an integer.
|
||||
Version.new(other.to_s)
|
||||
when Token
|
||||
if other.null?
|
||||
# Cannot compare `NULL` to `NULL`.
|
||||
return if null?
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
Version.new(other.to_s)
|
||||
when Version
|
||||
if other.null?
|
||||
# Cannot compare `NULL` to `NULL`.
|
||||
return if null?
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
other
|
||||
when nil
|
||||
return 1
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
# All `other.null?` cases are handled at this point.
|
||||
return -1 if null?
|
||||
|
||||
other = Version.new(other.to_s) if other.is_a? Token
|
||||
return unless other.is_a?(Version)
|
||||
return 0 if version == other.version
|
||||
return 1 if head? && !other.head?
|
||||
return -1 if !head? && other.head?
|
||||
@ -585,41 +624,64 @@ class Version
|
||||
|
||||
0
|
||||
end
|
||||
|
||||
sig { override.params(other: T.untyped).returns(T::Boolean) }
|
||||
def ==(other)
|
||||
# Makes sure that the same instance of Version::NULL
|
||||
# will never equal itself; normally Comparable#==
|
||||
# will return true for this regardless of the return
|
||||
# value of #<=>
|
||||
return false if null?
|
||||
|
||||
super
|
||||
end
|
||||
alias eql? ==
|
||||
|
||||
# @api public
|
||||
sig { returns(T.nilable(Token)) }
|
||||
def major
|
||||
return NULL_TOKEN if null?
|
||||
|
||||
tokens.first
|
||||
end
|
||||
|
||||
# @api public
|
||||
sig { returns(T.nilable(Token)) }
|
||||
def minor
|
||||
return NULL_TOKEN if null?
|
||||
|
||||
tokens.second
|
||||
end
|
||||
|
||||
# @api public
|
||||
sig { returns(T.nilable(Token)) }
|
||||
def patch
|
||||
return NULL_TOKEN if null?
|
||||
|
||||
tokens.third
|
||||
end
|
||||
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major_minor
|
||||
self.class.new([major, minor].compact.join("."))
|
||||
return self if null?
|
||||
|
||||
major_minor = T.must(tokens[0..1])
|
||||
major_minor.empty? ? NULL : self.class.new(major_minor.join("."))
|
||||
end
|
||||
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major_minor_patch
|
||||
self.class.new([major, minor, patch].compact.join("."))
|
||||
return self if null?
|
||||
|
||||
major_minor_patch = T.must(tokens[0..2])
|
||||
major_minor_patch.empty? ? NULL : self.class.new(major_minor_patch.join("."))
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def empty?
|
||||
version.empty?
|
||||
version&.empty? || false
|
||||
end
|
||||
|
||||
sig { returns(Integer) }
|
||||
@ -629,6 +691,8 @@ class Version
|
||||
|
||||
sig { returns(Float) }
|
||||
def to_f
|
||||
return Float::NAN if null?
|
||||
|
||||
version.to_f
|
||||
end
|
||||
|
||||
@ -639,10 +703,17 @@ class Version
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
version.dup
|
||||
version.to_s
|
||||
end
|
||||
alias to_str to_s
|
||||
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
return "#<Version::NULL>" if null?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
sig { returns(T.self_type) }
|
||||
def freeze
|
||||
tokens # Determine and store tokens before freezing
|
||||
@ -651,12 +722,12 @@ class Version
|
||||
|
||||
protected
|
||||
|
||||
sig { returns(String) }
|
||||
sig { returns(T.nilable(String)) }
|
||||
attr_reader :version
|
||||
|
||||
sig { returns(T::Array[Token]) }
|
||||
def tokens
|
||||
@tokens ||= tokenize
|
||||
@tokens ||= version&.scan(SCAN_PATTERN)&.map { |token| Token.create(T.cast(token, String)) } || []
|
||||
end
|
||||
|
||||
private
|
||||
@ -666,8 +737,6 @@ class Version
|
||||
(first > second) ? first : second
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Token]) }
|
||||
def tokenize
|
||||
version.scan(SCAN_PATTERN).map { |token| Token.create(T.cast(token, String)) }
|
||||
end
|
||||
# Represents the absence of a version.
|
||||
NULL = Version.new("NULL").tap { |v| v.instance_variable_set(:@version, nil) }.freeze
|
||||
end
|
||||
|
@ -1,33 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Version
|
||||
# A formula's HEAD version.
|
||||
# @see https://docs.brew.sh/Formula-Cookbook#unstable-versions-head Unstable versions (head)
|
||||
#
|
||||
# @api private
|
||||
class HeadVersion < Version
|
||||
sig { returns(T.nilable(String)) }
|
||||
attr_reader :commit
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@commit = @version[/^HEAD-(.+)$/, 1]
|
||||
end
|
||||
|
||||
sig { params(commit: T.nilable(String)).void }
|
||||
def update_commit(commit)
|
||||
@commit = commit
|
||||
@version = if commit
|
||||
"HEAD-#{commit}"
|
||||
else
|
||||
"HEAD"
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def head?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
@ -1,104 +0,0 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "singleton"
|
||||
|
||||
class Version
|
||||
# A pseudo-version representing the absence of a version.
|
||||
#
|
||||
# @api private
|
||||
class NullVersion < Version
|
||||
include Comparable
|
||||
include Singleton
|
||||
|
||||
sig { override.params(_other: T.untyped).returns(Integer) }
|
||||
def <=>(_other)
|
||||
-1
|
||||
end
|
||||
|
||||
sig { override.params(_other: T.untyped).returns(T::Boolean) }
|
||||
def eql?(_other)
|
||||
# Makes sure that the same instance of Version::NULL
|
||||
# will never equal itself; normally Comparable#==
|
||||
# will return true for this regardless of the return
|
||||
# value of #<=>
|
||||
false
|
||||
end
|
||||
|
||||
sig { override.returns(T::Boolean) }
|
||||
def detected_from_url?
|
||||
false
|
||||
end
|
||||
|
||||
sig { override.returns(T::Boolean) }
|
||||
def head?
|
||||
false
|
||||
end
|
||||
|
||||
sig { override.returns(T::Boolean) }
|
||||
def null?
|
||||
true
|
||||
end
|
||||
|
||||
# For {OS::Mac::Version} compatibility.
|
||||
sig { returns(T::Boolean) }
|
||||
def requires_nehalem_cpu?
|
||||
false
|
||||
end
|
||||
alias requires_sse4? requires_nehalem_cpu?
|
||||
alias requires_sse41? requires_nehalem_cpu?
|
||||
alias requires_sse42? requires_nehalem_cpu?
|
||||
alias requires_popcnt? requires_nehalem_cpu?
|
||||
alias outdated_release? requires_nehalem_cpu?
|
||||
|
||||
sig { override.returns(Token) }
|
||||
def major
|
||||
NULL_TOKEN
|
||||
end
|
||||
|
||||
sig { override.returns(Token) }
|
||||
def minor
|
||||
NULL_TOKEN
|
||||
end
|
||||
|
||||
sig { override.returns(Token) }
|
||||
def patch
|
||||
NULL_TOKEN
|
||||
end
|
||||
|
||||
sig { override.returns(T.self_type) }
|
||||
def major_minor
|
||||
self
|
||||
end
|
||||
|
||||
sig { override.returns(T.self_type) }
|
||||
def major_minor_patch
|
||||
self
|
||||
end
|
||||
|
||||
sig { override.returns(Float) }
|
||||
def to_f
|
||||
Float::NAN
|
||||
end
|
||||
|
||||
sig { override.returns(Integer) }
|
||||
def to_i
|
||||
0
|
||||
end
|
||||
|
||||
sig { override.returns(String) }
|
||||
def to_s
|
||||
""
|
||||
end
|
||||
alias to_str to_s
|
||||
|
||||
sig { override.returns(String) }
|
||||
def inspect
|
||||
"#<Version::NULL>"
|
||||
end
|
||||
end
|
||||
private_constant :NullVersion
|
||||
|
||||
# Represents the absence of a version.
|
||||
NULL = NullVersion.instance.freeze
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user