diff --git a/Library/Homebrew/ast_constants.rb b/Library/Homebrew/ast_constants.rb index 7622f0a2d3..cc778677fa 100644 --- a/Library/Homebrew/ast_constants.rb +++ b/Library/Homebrew/ast_constants.rb @@ -1,7 +1,7 @@ # typed: true # frozen_string_literal: true -require "macos_versions" +require "macos_version" FORMULA_COMPONENT_PRECEDENCE_LIST = [ [{ name: :include, type: :method_call }], @@ -29,7 +29,7 @@ FORMULA_COMPONENT_PRECEDENCE_LIST = [ [{ name: :depends_on, type: :method_call }], [{ name: :uses_from_macos, type: :method_call }], [{ name: :on_macos, type: :block_call }], - *MacOSVersions::SYMBOLS.keys.map do |os_name| + *MacOSVersion::SYMBOLS.keys.map do |os_name| [{ name: :"on_#{os_name}", type: :block_call }] end, [{ name: :on_system, type: :block_call }], diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index dd7aec3392..069c8b7d8f 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -461,7 +461,7 @@ esac # TODO: bump version when new macOS is released or announced # and also update references in docs/Installation.md, # https://github.com/Homebrew/install/blob/HEAD/install.sh and -# MacOSVersions::SYMBOLS +# MacOSVersion::SYMBOLS HOMEBREW_MACOS_NEWEST_UNSUPPORTED="14" # TODO: bump version when new macOS is released and also update # references in docs/Installation.md and diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 17c1c4611c..606470b528 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -549,8 +549,8 @@ module Cask return if min_os.blank? begin - min_os_string = OS::Mac::Version.new(min_os).strip_patch - rescue MacOSVersionError + min_os_string = MacOSVersion.new(min_os).strip_patch + rescue MacOSVersion::Error return end diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index 8932110cf9..1fe172a1ac 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -316,7 +316,7 @@ module Cask begin if @dsl.on_system_blocks_exist? [:arm, :intel].each do |arch| - MacOSVersions::SYMBOLS.each_key do |os_name| + MacOSVersion::SYMBOLS.each_key do |os_name| bottle_tag = ::Utils::Bottles::Tag.new(system: os_name, arch: arch) next unless bottle_tag.valid_combination? diff --git a/Library/Homebrew/cask/cask_loader.rb b/Library/Homebrew/cask/cask_loader.rb index 4c2302a8c8..0f3825ad7c 100644 --- a/Library/Homebrew/cask/cask_loader.rb +++ b/Library/Homebrew/cask/cask_loader.rb @@ -303,13 +303,13 @@ module Cask dep_type = dep_value.keys.first if dep_type == :== version_symbols = dep_value[dep_type].map do |version| - MacOSVersions::SYMBOLS.key(version) || version + MacOSVersion::SYMBOLS.key(version) || version end next [dep_key, version_symbols] end version_symbol = dep_value[dep_type].first - version_symbol = MacOSVersions::SYMBOLS.key(version_symbol) || version_symbol + version_symbol = MacOSVersion::SYMBOLS.key(version_symbol) || version_symbol [dep_key, "#{dep_type} :#{version_symbol}"] end.compact depends_on(**dep_hash) diff --git a/Library/Homebrew/cask/download.rb b/Library/Homebrew/cask/download.rb index 16fa062ecf..74b0d61373 100644 --- a/Library/Homebrew/cask/download.rb +++ b/Library/Homebrew/cask/download.rb @@ -32,9 +32,9 @@ module Cask @checksum ||= cask.sha256 if cask.sha256 != :no_check end - sig { override.returns(T.nilable(::Version)) } + sig { override.returns(T.nilable(Version)) } def version - @version ||= ::Version.create(cask.version) + @version ||= Version.create(cask.version) end sig { diff --git a/Library/Homebrew/cask/dsl/depends_on.rb b/Library/Homebrew/cask/dsl/depends_on.rb index 7af6ff40e0..e56faf0893 100644 --- a/Library/Homebrew/cask/dsl/depends_on.rb +++ b/Library/Homebrew/cask/dsl/depends_on.rb @@ -59,7 +59,7 @@ module Cask begin @macos = if args.count > 1 MacOSRequirement.new([args], comparator: "==") - elsif MacOSVersions::SYMBOLS.key?(args.first) + elsif MacOSVersion::SYMBOLS.key?(args.first) MacOSRequirement.new([args.first], comparator: "==") elsif (md = /^\s*(?<|>|[=<>]=)\s*:(?\S+)\s*$/.match(first_arg)) MacOSRequirement.new([T.must(md[:version]).to_sym], comparator: md[:comparator]) @@ -68,7 +68,7 @@ module Cask else # rubocop:disable Lint/DuplicateBranch MacOSRequirement.new([args.first], comparator: "==") end - rescue MacOSVersionError => e + rescue MacOSVersion::Error, TypeError => e raise "invalid 'depends_on macos' value: #{e}" end end diff --git a/Library/Homebrew/cask/macos.rb b/Library/Homebrew/cask/macos.rb index 1587de3456..8db4eeeb0a 100644 --- a/Library/Homebrew/cask/macos.rb +++ b/Library/Homebrew/cask/macos.rb @@ -1,8 +1,6 @@ # typed: true # frozen_string_literal: true -require "os/mac/version" - module OS module Mac module_function diff --git a/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb b/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb index dfd525d5bc..660fef326a 100644 --- a/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb +++ b/Library/Homebrew/dev-cmd/dispatch-build-bottle.rb @@ -53,9 +53,9 @@ module Homebrew os, arch = element.then do |s| tag = Utils::Bottles::Tag.from_symbol(s.to_sym) [tag.to_macos_version, tag.arch] - rescue ArgumentError, MacOSVersionError + rescue ArgumentError, MacOSVersion::Error os, arch = s.split("-", 2) - [MacOS::Version.new(os), arch&.to_sym] + [MacOSVersion.new(os), arch&.to_sym] end if arch.present? && arch != :x86_64 diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 1d0f56ab14..6ed3ef6092 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -767,16 +767,6 @@ class ChildProcessError < RuntimeError end end -# Raised when a macOS version is unsupported. -class MacOSVersionError < RuntimeError - attr_reader :version - - def initialize(version) - @version = version - super "unknown or unsupported macOS version: #{version.inspect}" - end -end - # Raised when `detected_perl_shebang` etc cannot detect the shebang. class ShebangDetectionError < RuntimeError def initialize(type, reason) diff --git a/Library/Homebrew/extend/on_system.rb b/Library/Homebrew/extend/on_system.rb index 7d8670a65f..49a07da88b 100644 --- a/Library/Homebrew/extend/on_system.rb +++ b/Library/Homebrew/extend/on_system.rb @@ -18,7 +18,7 @@ module OnSystem def self.os_condition_met?(os_name, or_condition = nil) return Homebrew::SimulateSystem.send("simulating_or_running_on_#{os_name}?") if BASE_OS_OPTIONS.include?(os_name) - raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name) + raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersion::SYMBOLS.key?(os_name) if or_condition.present? && [:or_newer, :or_older].exclude?(or_condition) raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}" @@ -26,13 +26,13 @@ module OnSystem return false if Homebrew::SimulateSystem.simulating_or_running_on_linux? - base_os = OS::Mac::Version.from_symbol(os_name) + base_os = MacOSVersion.from_symbol(os_name) current_os = if Homebrew::SimulateSystem.current_os == :macos # Assume the oldest macOS version when simulating a generic macOS version # Version::NULL is always treated as less than any other version. Version::NULL else - OS::Mac::Version.from_symbol(Homebrew::SimulateSystem.current_os) + MacOSVersion.from_symbol(Homebrew::SimulateSystem.current_os) end return current_os >= base_os if or_condition == :or_newer @@ -115,7 +115,7 @@ module OnSystem sig { params(base: Class).void } def self.setup_macos_methods(base) - MacOSVersions::SYMBOLS.each_key do |os_name| + MacOSVersion::SYMBOLS.each_key do |os_name| base.define_method("on_#{os_name}") do |or_condition = nil, &block| @on_system_blocks_exist = true diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb index d7920fa2fd..95f8e42e7a 100644 --- a/Library/Homebrew/extend/os/mac/diagnostic.rb +++ b/Library/Homebrew/extend/os/mac/diagnostic.rb @@ -445,7 +445,7 @@ module Homebrew path_version = sdk.path.basename.to_s[MacOS::SDK::VERSIONED_SDK_REGEX, 1] next true if path_version.blank? - sdk.version == MacOS::Version.new(path_version).strip_patch + sdk.version == MacOSVersion.new(path_version).strip_patch end if locator.source == :clt diff --git a/Library/Homebrew/extend/os/mac/hardware.rb b/Library/Homebrew/extend/os/mac/hardware.rb index fb3273b7df..cbe49c8424 100644 --- a/Library/Homebrew/extend/os/mac/hardware.rb +++ b/Library/Homebrew/extend/os/mac/hardware.rb @@ -5,7 +5,7 @@ module Hardware sig { params(version: T.nilable(Version)).returns(Symbol) } def self.oldest_cpu(version = nil) version = if version - MacOS::Version.new(version.to_s) + MacOSVersion.new(version.to_s) else MacOS.version end diff --git a/Library/Homebrew/extend/os/mac/readall.rb b/Library/Homebrew/extend/os/mac/readall.rb index 4f180a0550..a0a2e5c161 100644 --- a/Library/Homebrew/extend/os/mac/readall.rb +++ b/Library/Homebrew/extend/os/mac/readall.rb @@ -7,7 +7,7 @@ module Readall return true if os_name == :linux current_macos_version = if os_name.is_a?(Symbol) - MacOS::Version.from_symbol(os_name) + MacOSVersion.from_symbol(os_name) else MacOS.version end diff --git a/Library/Homebrew/extend/os/mac/simulate_system.rb b/Library/Homebrew/extend/os/mac/simulate_system.rb index 053d361869..62f0d2d3bb 100644 --- a/Library/Homebrew/extend/os/mac/simulate_system.rb +++ b/Library/Homebrew/extend/os/mac/simulate_system.rb @@ -9,7 +9,7 @@ module Homebrew sig { returns(T::Boolean) } def simulating_or_running_on_macos? - os.blank? || [:macos, *MacOSVersions::SYMBOLS.keys].include?(os) + os.blank? || [:macos, *MacOSVersion::SYMBOLS.keys].include?(os) end sig { returns(Symbol) } diff --git a/Library/Homebrew/extend/os/mac/utils/bottles.rb b/Library/Homebrew/extend/os/mac/utils/bottles.rb index 7d601f14f4..d0a11ad720 100644 --- a/Library/Homebrew/extend/os/mac/utils/bottles.rb +++ b/Library/Homebrew/extend/os/mac/utils/bottles.rb @@ -35,7 +35,7 @@ module Utils def find_older_compatible_tag(tag) tag_version = begin tag.to_macos_version - rescue MacOSVersionError + rescue MacOSVersion::Error nil end @@ -45,7 +45,7 @@ module Utils next if candidate.arch != tag.arch candidate.to_macos_version <= tag_version - rescue MacOSVersionError + rescue MacOSVersion::Error false end end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index cd0e48d073..f61f106a62 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -2249,7 +2249,7 @@ class Formula variations = {} - os_versions = [*MacOSVersions::SYMBOLS.keys, :linux] + os_versions = [*MacOSVersion::SYMBOLS.keys, :linux] begin if path.exist? && self.class.on_system_blocks_exist? diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index 8a07d0fc5a..c55db2f9a1 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -757,7 +757,7 @@ module Homebrew newest_committed_revision ||= previous_revision newest_committed_url ||= stable.url end - rescue MacOSVersionError + rescue MacOSVersion::Error break end @@ -893,7 +893,7 @@ module Homebrew # The formula has no variations, so all OS-version-arch triples depend on GCC. return false if variations.blank? - MacOSVersions::SYMBOLS.each_key do |macos_version| + MacOSVersion::SYMBOLS.each_key do |macos_version| [:arm, :intel].each do |arch| bottle_tag = Utils::Bottles::Tag.new(system: macos_version, arch: arch) next unless bottle_tag.valid_combination? diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index e293510307..d3514a050c 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -91,7 +91,7 @@ module Formulary # access them from within the formula's class scope. mod.const_set(:BUILD_FLAGS, flags) mod.module_eval(contents, path) - rescue NameError, ArgumentError, ScriptError, MethodDeprecatedError, MacOSVersionError => e + rescue NameError, ArgumentError, ScriptError, MethodDeprecatedError, MacOSVersion::Error => e if e.is_a?(Ignorable::ExceptionMixin) e.ignore else @@ -223,7 +223,7 @@ module Formulary when :arch req["version"]&.to_sym when :macos, :maximum_macos - MacOSVersions::SYMBOLS.key(req["version"]) + MacOSVersion::SYMBOLS.key(req["version"]) else req["version"] end diff --git a/Library/Homebrew/github_runner.rb b/Library/Homebrew/github_runner.rb index 91da9f7454..46086288c3 100644 --- a/Library/Homebrew/github_runner.rb +++ b/Library/Homebrew/github_runner.rb @@ -8,7 +8,7 @@ class GitHubRunner < T::Struct const :platform, Symbol const :arch, Symbol const :spec, T.any(LinuxRunnerSpec, MacOSRunnerSpec) - const :macos_version, T.nilable(OS::Mac::Version) + const :macos_version, T.nilable(MacOSVersion) prop :active, T::Boolean, default: false sig { returns(T::Boolean) } diff --git a/Library/Homebrew/github_runner_matrix.rb b/Library/Homebrew/github_runner_matrix.rb index 84fc2bd978..2154c968f0 100644 --- a/Library/Homebrew/github_runner_matrix.rb +++ b/Library/Homebrew/github_runner_matrix.rb @@ -90,7 +90,7 @@ class GitHubRunnerMatrix platform: Symbol, arch: Symbol, spec: RunnerSpec, - macos_version: T.nilable(OS::Mac::Version), + macos_version: T.nilable(MacOSVersion), ).returns(GitHubRunner) } def create_runner(platform, arch, spec, macos_version = nil) @@ -120,8 +120,8 @@ class GitHubRunnerMatrix ephemeral_suffix << "-deps" if @dependent_matrix ephemeral_suffix.freeze - MacOSVersions::SYMBOLS.each_value do |version| - macos_version = OS::Mac::Version.new(version) + MacOSVersion::SYMBOLS.each_value do |version| + macos_version = MacOSVersion.new(version) next if macos_version.unsupported_release? # Intel Big Sur is a bit slower than the other runners, diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index b59bcdc6ca..33a863003c 100644 --- a/Library/Homebrew/global.rb +++ b/Library/Homebrew/global.rb @@ -73,7 +73,7 @@ HOMEBREW_BOTTLES_EXTNAME_REGEX = /\.([a-z0-9_]+)\.bottle\.(?:(\d+)\.)?tar\.gz$/. require "extend/module" require "env_config" -require "macos_versions" +require "macos_version" require "os" require "messages" require "default_prefix" diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb index aac47e201c..093103f448 100644 --- a/Library/Homebrew/language/python.rb +++ b/Library/Homebrew/language/python.rb @@ -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") diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index 06eaf7bf71..acef02e986 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -974,7 +974,7 @@ module Homebrew end end - res_current = resource.version + res_current = T.must(resource.version) res_latest = Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(resource, v) }) return status_hash(resource, "error", ["Unable to get versions"], verbose: verbose) if res_latest.blank? diff --git a/Library/Homebrew/livecheck/strategy/sparkle.rb b/Library/Homebrew/livecheck/strategy/sparkle.rb index 4fc45aa2c7..311547ce8d 100644 --- a/Library/Homebrew/livecheck/strategy/sparkle.rb +++ b/Library/Homebrew/livecheck/strategy/sparkle.rb @@ -107,8 +107,8 @@ module Homebrew if (minimum_system_version = item.elements["minimumSystemVersion"]&.text&.gsub(/\A\D+|\D+\z/, "")) macos_minimum_system_version = begin - OS::Mac::Version.new(minimum_system_version).strip_patch - rescue MacOSVersionError + MacOSVersion.new(minimum_system_version).strip_patch + rescue MacOSVersion::Error nil end diff --git a/Library/Homebrew/macos_version.rb b/Library/Homebrew/macos_version.rb new file mode 100644 index 0000000000..988e1621cb --- /dev/null +++ b/Library/Homebrew/macos_version.rb @@ -0,0 +1,162 @@ +# typed: true +# frozen_string_literal: true + +require "version" + +# A macOS version. +# +# @api private +class MacOSVersion < Version + # Raised when a macOS version is unsupported. + class Error < RuntimeError + sig { returns(T.nilable(T.any(String, Symbol))) } + attr_reader :version + + def initialize(version) + @version = version + super "unknown or unsupported macOS version: #{version.inspect}" + end + end + + # NOTE: When removing symbols here, ensure that they are added + # to `DEPRECATED_MACOS_VERSIONS` in `MacOSRequirement`. + SYMBOLS = { + ventura: "13", + monterey: "12", + big_sur: "11", + catalina: "10.15", + mojave: "10.14", + high_sierra: "10.13", + sierra: "10.12", + el_capitan: "10.11", + }.freeze + + sig { params(version: Symbol).returns(T.attached_class) } + def self.from_symbol(version) + str = SYMBOLS.fetch(version) { raise MacOSVersion::Error, version } + new(str) + end + + sig { params(version: T.nilable(String)).void } + def initialize(version) + raise MacOSVersion::Error, version unless /\A1\d+(?:\.\d+){0,2}\Z/.match?(version) + + super(version) + + @comparison_cache = {} + end + + sig { override.params(other: T.untyped).returns(T.nilable(Integer)) } + def <=>(other) + return @comparison_cache[other] if @comparison_cache.key?(other) + + result = case other + when Symbol + if SYMBOLS.key?(other) && to_sym == other + 0 + else + v = SYMBOLS.fetch(other) { other.to_s } + 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) + else + major_minor + end + end + + sig { returns(Symbol) } + def to_sym + return @sym if defined?(@sym) + + sym = SYMBOLS.invert.fetch(strip_patch.to_s, :dunno) + + @sym = sym unless frozen? + + sym + end + + sig { returns(String) } + def pretty_name + 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) } + def outdated_release? + self < HOMEBREW_MACOS_OLDEST_SUPPORTED + end + + sig { returns(T::Boolean) } + def prerelease? + self >= HOMEBREW_MACOS_NEWEST_UNSUPPORTED + end + + sig { returns(T::Boolean) } + def unsupported_release? + outdated_release? || prerelease? + end + + sig { returns(T::Boolean) } + def requires_nehalem_cpu? + return false if null? + + require "hardware" + + return Hardware.oldest_cpu(self) == :nehalem if Hardware::CPU.intel? + + raise ArgumentError, "Unexpected architecture: #{Hardware::CPU.arch}. This only works with Intel architecture." + end + # https://en.wikipedia.org/wiki/Nehalem_(microarchitecture) + alias requires_sse4? requires_nehalem_cpu? + alias requires_sse41? requires_nehalem_cpu? + alias requires_sse42? requires_nehalem_cpu? + alias requires_popcnt? requires_nehalem_cpu? + + # Represents the absence of a version. + # NOTE: Constructor needs to called with an arbitrary macOS-like version which is then set to `nil`. + NULL = MacOSVersion.new("10.0").tap { |v| v.instance_variable_set(:@version, nil) }.freeze +end + +require "lazy_object" + +MacOSVersionError = LazyObject.new do # rubocop:disable Style/MutableConstant + # odeprecated "MacOSVersionError", "MacOSVersion::Error" + MacOSVersion::Error +end + +module MacOSVersions + SYMBOLS = LazyObject.new do # rubocop:disable Style/MutableConstant + # odeprecated "MacOSVersions::SYMBOLS", "MacOSVersion::SYMBOLS" + MacOSVersion::SYMBOLS + end +end + +module OS + module Mac + # TODO: Replace `::Version` with `Version` when this is removed. + Version = LazyObject.new do # rubocop:disable Style/MutableConstant + # odeprecated "OS::Mac::Version", "MacOSVersion" + MacOSVersion + end + end +end diff --git a/Library/Homebrew/macos_versions.rb b/Library/Homebrew/macos_versions.rb deleted file mode 100644 index 16d4bd47e4..0000000000 --- a/Library/Homebrew/macos_versions.rb +++ /dev/null @@ -1,20 +0,0 @@ -# typed: true -# frozen_string_literal: true - -# Helper functions for querying operating system information. -# -# @api private -module MacOSVersions - # TODO: when removing symbols here, ensure that they are added to - # DEPRECATED_MACOS_VERSIONS in MacOSRequirement. - SYMBOLS = { - ventura: "13", - monterey: "12", - big_sur: "11", - catalina: "10.15", - mojave: "10.14", - high_sierra: "10.13", - sierra: "10.12", - el_capitan: "10.11", - }.freeze -end diff --git a/Library/Homebrew/os.rb b/Library/Homebrew/os.rb index 4743f6b727..899fbf10b7 100644 --- a/Library/Homebrew/os.rb +++ b/Library/Homebrew/os.rb @@ -55,6 +55,7 @@ module OS if OS.mac? require "os/mac" + require "hardware" # Don't tell people to report issues on unsupported configurations. if !OS::Mac.version.prerelease? && !OS::Mac.version.outdated_release? && diff --git a/Library/Homebrew/os/linux.rb b/Library/Homebrew/os/linux.rb index 15d096bd97..709dd2d57e 100644 --- a/Library/Homebrew/os/linux.rb +++ b/Library/Homebrew/os/linux.rb @@ -53,11 +53,11 @@ module OS raise "Loaded OS::Linux on generic OS!" if ENV["HOMEBREW_TEST_GENERIC_OS"] def self.version - ::Version::NULL + MacOSVersion::NULL end def self.full_version - ::Version::NULL + MacOSVersion::NULL end def self.languages diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index 3936b46d5f..f49766082f 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -1,7 +1,8 @@ # typed: true # frozen_string_literal: true -require "os/mac/version" +require "macos_version" + require "os/mac/xcode" require "os/mac/sdk" require "os/mac/keg" @@ -18,25 +19,25 @@ module OS # This can be compared to numerics, strings, or symbols # using the standard Ruby Comparable methods. - sig { returns(Version) } + sig { returns(MacOSVersion) } def self.version @version ||= full_version.strip_patch end # This can be compared to numerics, strings, or symbols # using the standard Ruby Comparable methods. - sig { returns(Version) } + sig { returns(MacOSVersion) } def self.full_version @full_version ||= if ENV["HOMEBREW_FAKE_EL_CAPITAN"] # for Portable Ruby building - Version.new("10.11.6") + MacOSVersion.new("10.11.6") else - Version.new(VERSION) + MacOSVersion.new(VERSION) end end sig { params(version: String).void } def self.full_version=(version) - @full_version = Version.new(version.chomp) + @full_version = MacOSVersion.new(version.chomp) @version = nil end diff --git a/Library/Homebrew/os/mac/sdk.rb b/Library/Homebrew/os/mac/sdk.rb index 09cc68e61c..baa2b55985 100644 --- a/Library/Homebrew/os/mac/sdk.rb +++ b/Library/Homebrew/os/mac/sdk.rb @@ -1,8 +1,6 @@ # typed: true # frozen_string_literal: true -require "os/mac/version" - module OS module Mac # Class representing a macOS SDK. @@ -12,7 +10,7 @@ module OS # 11.x SDKs are explicitly excluded - we want the MacOSX11.sdk symlink instead. VERSIONED_SDK_REGEX = /MacOSX(10\.\d+|\d+)\.sdk$/.freeze - sig { returns(OS::Mac::Version) } + sig { returns(MacOSVersion) } attr_reader :version sig { returns(Pathname) } @@ -21,7 +19,7 @@ module OS sig { returns(Symbol) } attr_reader :source - sig { params(version: OS::Mac::Version, path: T.any(String, Pathname), source: Symbol).void } + sig { params(version: MacOSVersion, path: T.any(String, Pathname), source: Symbol).void } def initialize(version, path, source) @version = version @path = Pathname.new(path) @@ -39,7 +37,7 @@ module OS class NoSDKError < StandardError; end - sig { params(version: OS::Mac::Version).returns(SDK) } + sig { params(version: MacOSVersion).returns(SDK) } def sdk_for(version) sdk = all_sdks.find { |s| s.version == version } raise NoSDKError if sdk.nil? @@ -77,7 +75,7 @@ module OS @all_sdks end - sig { params(version: T.nilable(OS::Mac::Version)).returns(T.nilable(SDK)) } + sig { params(version: T.nilable(MacOSVersion)).returns(T.nilable(SDK)) } def sdk_if_applicable(version = nil) sdk = begin if version.blank? @@ -110,7 +108,7 @@ module OS all_sdks.max_by(&:version) end - sig { params(sdk_path: Pathname).returns(T.nilable(OS::Mac::Version)) } + sig { params(sdk_path: Pathname).returns(T.nilable(MacOSVersion)) } def read_sdk_version(sdk_path) sdk_settings = sdk_path/"SDKSettings.json" sdk_settings_string = sdk_settings.read if sdk_settings.exist? @@ -131,8 +129,8 @@ module OS return if version_string.blank? begin - OS::Mac::Version.new(version_string).strip_patch - rescue MacOSVersionError + MacOSVersion.new(version_string).strip_patch + rescue MacOSVersion::Error nil end end diff --git a/Library/Homebrew/os/mac/version.rb b/Library/Homebrew/os/mac/version.rb deleted file mode 100644 index 6dcda2f571..0000000000 --- a/Library/Homebrew/os/mac/version.rb +++ /dev/null @@ -1,95 +0,0 @@ -# typed: true -# frozen_string_literal: true - -require "exceptions" -require "hardware" -require "version" - -module OS - module Mac - # A macOS version. - # - # @api private - class Version < ::Version - sig { params(version: Symbol).returns(T.attached_class) } - def self.from_symbol(version) - str = MacOSVersions::SYMBOLS.fetch(version) { raise MacOSVersionError, version } - new(str) - end - - sig { params(value: T.nilable(String)).void } - def initialize(value) - version ||= value - - raise MacOSVersionError, version unless /\A1\d+(?:\.\d+){0,2}\Z/.match?(version) - - super(version) - - @comparison_cache = {} - end - - sig { override.params(other: T.untyped).returns(T.nilable(Integer)) } - def <=>(other) - @comparison_cache.fetch(other) do - 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)) - end - end - end - - sig { returns(T.self_type) } - def strip_patch - # Big Sur is 11.x but Catalina is 10.15.x. - if T.must(major) >= 11 - self.class.new(major.to_s) - else - major_minor - end - end - - sig { returns(Symbol) } - def to_sym - @to_sym ||= MacOSVersions::SYMBOLS.invert.fetch(strip_patch.to_s, :dunno) - end - - sig { returns(String) } - def pretty_name - @pretty_name ||= to_sym.to_s.split("_").map(&:capitalize).join(" ").freeze - end - - sig { returns(T::Boolean) } - def outdated_release? - self < HOMEBREW_MACOS_OLDEST_SUPPORTED - end - - sig { returns(T::Boolean) } - def prerelease? - self >= HOMEBREW_MACOS_NEWEST_UNSUPPORTED - end - - sig { returns(T::Boolean) } - def unsupported_release? - outdated_release? || prerelease? - end - - # For {OS::Mac::Version} compatibility. - sig { returns(T::Boolean) } - def requires_nehalem_cpu? - unless Hardware::CPU.intel? - raise "Unexpected architecture: #{Hardware::CPU.arch}. This only works with Intel architecture." - end - - Hardware.oldest_cpu(self) == :nehalem - end - # https://en.wikipedia.org/wiki/Nehalem_(microarchitecture) - # Ensure any extra methods are also added to version/null.rb - alias requires_sse4? requires_nehalem_cpu? - alias requires_sse41? requires_nehalem_cpu? - alias requires_sse42? requires_nehalem_cpu? - alias requires_popcnt? requires_nehalem_cpu? - end - end -end diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 4cc61a5762..e1b28f87d8 100755 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -15,7 +15,7 @@ module OS # Bump these when a new version is available from the App Store and our # CI systems have been updated. # This may be a beta version for a beta macOS. - sig { params(macos: MacOS::Version).returns(String) } + sig { params(macos: MacOSVersion).returns(String) } def self.latest_version(macos: MacOS.version) latest_stable = "14.3" case macos @@ -136,12 +136,12 @@ module OS @sdk_locator ||= XcodeSDKLocator.new end - sig { params(version: T.nilable(MacOS::Version)).returns(T.nilable(SDK)) } + sig { params(version: T.nilable(MacOSVersion)).returns(T.nilable(SDK)) } def self.sdk(version = nil) sdk_locator.sdk_if_applicable(version) end - sig { params(version: T.nilable(MacOS::Version)).returns(T.nilable(Pathname)) } + sig { params(version: T.nilable(MacOSVersion)).returns(T.nilable(Pathname)) } def self.sdk_path(version = nil) sdk(version)&.path end @@ -283,12 +283,12 @@ module OS @sdk_locator ||= CLTSDKLocator.new end - sig { params(version: T.nilable(MacOS::Version)).returns(T.nilable(SDK)) } + sig { params(version: T.nilable(MacOSVersion)).returns(T.nilable(SDK)) } def self.sdk(version = nil) sdk_locator.sdk_if_applicable(version) end - sig { params(version: T.nilable(MacOS::Version)).returns(T.nilable(Pathname)) } + sig { params(version: T.nilable(MacOSVersion)).returns(T.nilable(Pathname)) } def self.sdk_path(version = nil) sdk(version)&.path end diff --git a/Library/Homebrew/readall.rb b/Library/Homebrew/readall.rb index 3a777ffe37..c093811d8f 100644 --- a/Library/Homebrew/readall.rb +++ b/Library/Homebrew/readall.rb @@ -77,7 +77,7 @@ module Readall success = false unless valid_casks?(tap.cask_files) else arches = [:arm, :intel] - os_names = [*MacOSVersions::SYMBOLS.keys, :linux] + os_names = [*MacOSVersion::SYMBOLS.keys, :linux] arches.each do |arch| os_names.each do |os_name| bottle_tag = Utils::Bottles::Tag.new(system: os_name, arch: arch) diff --git a/Library/Homebrew/requirements/macos_requirement.rb b/Library/Homebrew/requirements/macos_requirement.rb index ddcba52f97..adad00255e 100644 --- a/Library/Homebrew/requirements/macos_requirement.rb +++ b/Library/Homebrew/requirements/macos_requirement.rb @@ -21,11 +21,11 @@ class MacOSRequirement < Requirement def initialize(tags = [], comparator: ">=") @version = begin if comparator == "==" && tags.first.respond_to?(:map) - tags.first.map { |s| OS::Mac::Version.from_symbol(s) } + tags.first.map { |s| MacOSVersion.from_symbol(s) } else - OS::Mac::Version.from_symbol(tags.first) unless tags.empty? + MacOSVersion.from_symbol(tags.first) unless tags.empty? end - rescue MacOSVersionError => e + rescue MacOSVersion::Error => e if DISABLED_MACOS_VERSIONS.include?(e.version) odisabled "depends_on :macos => :#{e.version}" elsif DEPRECATED_MACOS_VERSIONS.include?(e.version) @@ -41,7 +41,7 @@ class MacOSRequirement < Requirement end # Otherwise fallback to the oldest allowed if comparator is >=. - OS::Mac::Version.new(HOMEBREW_MACOS_OLDEST_ALLOWED) if comparator == ">=" + MacOSVersion.new(HOMEBREW_MACOS_OLDEST_ALLOWED) if comparator == ">=" end @comparator = comparator diff --git a/Library/Homebrew/resource.rb b/Library/Homebrew/resource.rb index 73fc5b4a26..c2d18e2cd5 100644 --- a/Library/Homebrew/resource.rb +++ b/Library/Homebrew/resource.rb @@ -190,12 +190,15 @@ 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? - @version = case val - when String then Version.create(val) - when Version then val + @version = case T.unsafe(val) + when String + val.blank? ? Version::NULL : Version.new(val) + when Version + val else # TODO: This can probably go if/when typechecking is enforced in taps. raise TypeError, "version '#{val.inspect}' should be a string" diff --git a/Library/Homebrew/rubocops/cask/constants/stanza.rb b/Library/Homebrew/rubocops/cask/constants/stanza.rb index cca0537428..54fcdb73fc 100644 --- a/Library/Homebrew/rubocops/cask/constants/stanza.rb +++ b/Library/Homebrew/rubocops/cask/constants/stanza.rb @@ -5,11 +5,11 @@ module RuboCop module Cask # Constants available globally for use in all cask cops. module Constants - ON_SYSTEM_METHODS = [:arm, :intel, *MacOSVersions::SYMBOLS.keys].map { |option| :"on_#{option}" }.freeze + ON_SYSTEM_METHODS = [:arm, :intel, *MacOSVersion::SYMBOLS.keys].map { |option| :"on_#{option}" }.freeze ON_SYSTEM_METHODS_STANZA_ORDER = [ :arm, :intel, - *MacOSVersions::SYMBOLS.reverse_each.to_h.keys, # Oldest OS blocks first since that's more common in Casks. + *MacOSVersion::SYMBOLS.reverse_each.to_h.keys, # Oldest OS blocks first since that's more common in Casks. ].map { |option, _| :"on_#{option}" }.freeze STANZA_GROUPS = [ diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb index 86801438ab..2ad09eaa4b 100644 --- a/Library/Homebrew/rubocops/extend/formula_cop.rb +++ b/Library/Homebrew/rubocops/extend/formula_cop.rb @@ -212,7 +212,7 @@ module RuboCop end def on_system_methods - @on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersions::SYMBOLS.keys].map do |m| + @on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersion::SYMBOLS.keys].map do |m| :"on_#{m}" end end diff --git a/Library/Homebrew/rubocops/lines.rb b/Library/Homebrew/rubocops/lines.rb index 1967bc4ca7..0fbe27452a 100644 --- a/Library/Homebrew/rubocops/lines.rb +++ b/Library/Homebrew/rubocops/lines.rb @@ -1,7 +1,7 @@ # typed: true # frozen_string_literal: true -require "macos_versions" +require "macos_version" require "rubocops/extend/formula_cop" require "rubocops/shared/on_system_conditionals_helper" diff --git a/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb b/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb index 432b42ed5e..c6e0142afb 100644 --- a/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb +++ b/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb @@ -1,7 +1,7 @@ # typed: true # frozen_string_literal: true -require "macos_versions" +require "macos_version" require "rubocops/shared/helper_functions" module RuboCop @@ -15,7 +15,7 @@ module RuboCop ARCH_OPTIONS = [:arm, :intel].freeze BASE_OS_OPTIONS = [:macos, :linux].freeze - MACOS_VERSION_OPTIONS = MacOSVersions::SYMBOLS.keys.freeze + MACOS_VERSION_OPTIONS = MacOSVersion::SYMBOLS.keys.freeze ON_SYSTEM_OPTIONS = [*ARCH_OPTIONS, *BASE_OS_OPTIONS, *MACOS_VERSION_OPTIONS, :system].freeze MACOS_VERSION_CONDITIONALS = { diff --git a/Library/Homebrew/simulate_system.rb b/Library/Homebrew/simulate_system.rb index 741aa41b48..055ffa072d 100644 --- a/Library/Homebrew/simulate_system.rb +++ b/Library/Homebrew/simulate_system.rb @@ -11,7 +11,7 @@ module Homebrew sig { params(new_os: Symbol).void } def os=(new_os) - os_options = [:macos, :linux, *MacOSVersions::SYMBOLS.keys] + os_options = [:macos, :linux, *MacOSVersion::SYMBOLS.keys] raise "Unknown OS: #{new_os}" unless os_options.include?(new_os) @os = new_os @@ -31,7 +31,7 @@ module Homebrew sig { returns(T::Boolean) } def simulating_or_running_on_macos? - [:macos, *MacOSVersions::SYMBOLS.keys].include?(os) + [:macos, *MacOSVersion::SYMBOLS.keys].include?(os) end sig { returns(T::Boolean) } diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index b9f83b6c5f..b6474b857a 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -11,7 +11,7 @@ require "dependency_collector" require "utils/bottles" require "patch" require "compilers" -require "os/mac/version" +require "macos_version" require "extend/on_system" class SoftwareSpec @@ -203,8 +203,8 @@ class SoftwareSpec return if Homebrew::SimulateSystem.current_os == :macos && !bounds.key?(:since) if Homebrew::SimulateSystem.current_os != :macos - current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os) - since_os = MacOS::Version.from_symbol(bounds[:since]) if bounds.key?(:since) + current_os = MacOSVersion.from_symbol(Homebrew::SimulateSystem.current_os) + since_os = MacOSVersion.from_symbol(bounds[:since]) if bounds.key?(:since) return if current_os >= since_os end end @@ -609,7 +609,7 @@ class BottleSpecification # Give arm64 bottles a higher priority so they are first priority = (tag.arch == :arm64) ? "2" : "1" "#{priority}.#{version}_#{tag}" - rescue MacOSVersionError + rescue MacOSVersion::Error # Sort non-MacOS tags below MacOS tags. "0.#{tag}" end diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb index a5ba02d5ea..3258c4e34c 100644 --- a/Library/Homebrew/tab.rb +++ b/Library/Homebrew/tab.rb @@ -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 diff --git a/Library/Homebrew/test/cask/cask_spec.rb b/Library/Homebrew/test/cask/cask_spec.rb index fab20eb310..4e465b1156 100644 --- a/Library/Homebrew/test/cask/cask_spec.rb +++ b/Library/Homebrew/test/cask/cask_spec.rb @@ -220,7 +220,7 @@ describe Cask::Cask, :cask do context "when loaded from cask file" do it "returns expected hash" do - allow(MacOS).to receive(:version).and_return(MacOS::Version.new("13")) + allow(MacOS).to receive(:version).and_return(MacOSVersion.new("13")) hash = Cask::CaskLoader.load("everything").to_h @@ -304,7 +304,7 @@ describe Cask::Cask, :cask do catalina: "10.15", mojave: "10.14", } - stub_const("MacOSVersions::SYMBOLS", symbols) + stub_const("MacOSVersion::SYMBOLS", symbols) # For consistency, always run on Monterey and ARM MacOS.full_version = "12" diff --git a/Library/Homebrew/test/cask/dsl/caveats_spec.rb b/Library/Homebrew/test/cask/dsl/caveats_spec.rb index 3108ace46c..dd47a8a79d 100644 --- a/Library/Homebrew/test/cask/dsl/caveats_spec.rb +++ b/Library/Homebrew/test/cask/dsl/caveats_spec.rb @@ -16,7 +16,7 @@ describe Cask::DSL::Caveats, :cask do let(:cask) { instance_double(Cask::Cask) } it "points to System Preferences on macOS Monterey and earlier" do - allow(MacOS).to receive(:version).and_return(MacOS::Version.new("12")) + allow(MacOS).to receive(:version).and_return(MacOSVersion.new("12")) caveats.eval_caveats do kext end @@ -24,7 +24,7 @@ describe Cask::DSL::Caveats, :cask do end it "points to System Settings on macOS Ventura and later" do - allow(MacOS).to receive(:version).and_return(MacOS::Version.new("13")) + allow(MacOS).to receive(:version).and_return(MacOSVersion.new("13")) caveats.eval_caveats do kext end diff --git a/Library/Homebrew/test/dev-cmd/determine-test-runners_spec.rb b/Library/Homebrew/test/dev-cmd/determine-test-runners_spec.rb index c66583052d..c3e24cd988 100644 --- a/Library/Homebrew/test/dev-cmd/determine-test-runners_spec.rb +++ b/Library/Homebrew/test/dev-cmd/determine-test-runners_spec.rb @@ -22,8 +22,8 @@ describe "brew determine-test-runners" do end let(:all_runners) do out = [] - MacOSVersions::SYMBOLS.each_value do |v| - macos_version = OS::Mac::Version.new(v) + MacOSVersion::SYMBOLS.each_value do |v| + macos_version = MacOSVersion.new(v) next if macos_version.unsupported_release? out << v diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 511d45baf4..0cb2279d80 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -978,10 +978,10 @@ describe Formula do catalina: "10.15", mojave: "10.14", } - stub_const("MacOSVersions::SYMBOLS", symbols) + stub_const("MacOSVersion::SYMBOLS", symbols) # For consistency, always run on Monterey and ARM - allow(MacOS).to receive(:version).and_return(MacOS::Version.new("12")) + allow(MacOS).to receive(:version).and_return(MacOSVersion.new("12")) allow(Hardware::CPU).to receive(:type).and_return(:arm) formula_path.dirname.mkpath diff --git a/Library/Homebrew/test/github_runner_matrix_spec.rb b/Library/Homebrew/test/github_runner_matrix_spec.rb index 12e9ba8e37..c9c0c361fe 100644 --- a/Library/Homebrew/test/github_runner_matrix_spec.rb +++ b/Library/Homebrew/test/github_runner_matrix_spec.rb @@ -13,7 +13,7 @@ describe GitHubRunnerMatrix do end let(:newest_supported_macos) do - MacOSVersions::SYMBOLS.find { |_, v| !OS::Mac::Version.new(v).prerelease? } + MacOSVersion::SYMBOLS.find { |_, v| !MacOSVersion.new(v).prerelease? } end let(:testball) { TestRunnerFormula.new(Testball.new) } diff --git a/Library/Homebrew/test/github_runner_spec.rb b/Library/Homebrew/test/github_runner_spec.rb index f869363f21..bcbadf07bc 100644 --- a/Library/Homebrew/test/github_runner_spec.rb +++ b/Library/Homebrew/test/github_runner_spec.rb @@ -5,7 +5,7 @@ require "github_runner" describe GitHubRunner do let(:runner) do spec = MacOSRunnerSpec.new(name: "macOS 11-arm64", runner: "11-arm64", timeout: 90, cleanup: true) - version = OS::Mac::Version.new("11") + version = MacOSVersion.new("11") described_class.new(platform: :macos, arch: :arm64, spec: spec, macos_version: version) end diff --git a/Library/Homebrew/test/os/mac/version_spec.rb b/Library/Homebrew/test/macos_version_spec.rb similarity index 85% rename from Library/Homebrew/test/os/mac/version_spec.rb rename to Library/Homebrew/test/macos_version_spec.rb index 20c7734c05..34a010833d 100644 --- a/Library/Homebrew/test/os/mac/version_spec.rb +++ b/Library/Homebrew/test/macos_version_spec.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true -require "version" -require "os/mac/version" +require "macos_version" -describe OS::Mac::Version do +describe MacOSVersion do let(:version) { described_class.new("10.14") } let(:big_sur_major) { described_class.new("11.0") } let(:big_sur_update) { described_class.new("11.1") } @@ -15,16 +14,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" @@ -59,7 +53,7 @@ describe OS::Mac::Version do it "raises an error if the version is not a valid macOS version" do expect do described_class.new("1.2") - end.to raise_error(MacOSVersionError, 'unknown or unsupported macOS version: "1.2"') + end.to raise_error(MacOSVersion::Error, 'unknown or unsupported macOS version: "1.2"') end it "creates a new version from a valid macOS version" do @@ -72,7 +66,7 @@ describe OS::Mac::Version do it "raises an error if the symbol is not a valid macOS version" do expect do described_class.from_symbol(:foo) - end.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :foo") + end.to raise_error(MacOSVersion::Error, "unknown or unsupported macOS version: :foo") end it "creates a new version from a valid macOS version" do @@ -86,7 +80,7 @@ describe OS::Mac::Version do expect(described_class.new("10.14").pretty_name).to eq("Mojave") end - specify "#requires_nehalem_cpu?" do + specify "#requires_nehalem_cpu?", :needs_macos do expect(Hardware::CPU).to receive(:type).at_least(:twice).and_return(:intel) expect(described_class.new("10.14").requires_nehalem_cpu?).to be true expect(described_class.new("10.12").requires_nehalem_cpu?).to be false diff --git a/Library/Homebrew/test/os/mac/diagnostic_spec.rb b/Library/Homebrew/test/os/mac/diagnostic_spec.rb index 314dd7ef78..b2183082ae 100644 --- a/Library/Homebrew/test/os/mac/diagnostic_spec.rb +++ b/Library/Homebrew/test/os/mac/diagnostic_spec.rb @@ -8,7 +8,7 @@ describe Homebrew::Diagnostic::Checks do specify "#check_for_unsupported_macos" do ENV.delete("HOMEBREW_DEVELOPER") - macos_version = OS::Mac::Version.new("10.14") + macos_version = MacOSVersion.new("10.14") allow(OS::Mac).to receive(:version).and_return(macos_version) allow(OS::Mac).to receive(:full_version).and_return(macos_version) allow(OS::Mac.version).to receive(:outdated_release?).and_return(false) @@ -19,7 +19,7 @@ describe Homebrew::Diagnostic::Checks do end specify "#check_if_xcode_needs_clt_installed" do - macos_version = OS::Mac::Version.new("10.11") + macos_version = MacOSVersion.new("10.11") allow(OS::Mac).to receive(:version).and_return(macos_version) allow(OS::Mac).to receive(:full_version).and_return(macos_version) allow(OS::Mac::Xcode).to receive(:installed?).and_return(true) @@ -31,7 +31,7 @@ describe Homebrew::Diagnostic::Checks do end specify "#check_ruby_version" do - macos_version = OS::Mac::Version.new("10.12") + macos_version = MacOSVersion.new("10.12") allow(OS::Mac).to receive(:version).and_return(macos_version) allow(OS::Mac).to receive(:full_version).and_return(macos_version) stub_const("RUBY_VERSION", "1.8.6") @@ -41,7 +41,7 @@ describe Homebrew::Diagnostic::Checks do end describe "#check_if_supported_sdk_available" do - let(:macos_version) { OS::Mac::Version.new("11") } + let(:macos_version) { MacOSVersion.new("11") } before do allow(DevelopmentTools).to receive(:installed?).and_return(true) @@ -87,8 +87,8 @@ describe Homebrew::Diagnostic::Checks do it "doesn't trigger when SDK versions are as expected" do allow(OS::Mac).to receive(:sdk_locator).and_return(OS::Mac::CLT.sdk_locator) allow_any_instance_of(OS::Mac::CLTSDKLocator).to receive(:all_sdks).and_return([ - OS::Mac::SDK.new(OS::Mac::Version.new("11"), "/some/path/MacOSX.sdk", :clt), - OS::Mac::SDK.new(OS::Mac::Version.new("10.15"), "/some/path/MacOSX10.15.sdk", :clt), + OS::Mac::SDK.new(MacOSVersion.new("11"), "/some/path/MacOSX.sdk", :clt), + OS::Mac::SDK.new(MacOSVersion.new("10.15"), "/some/path/MacOSX10.15.sdk", :clt), ]) expect(checks.check_broken_sdks).to be_nil @@ -96,7 +96,7 @@ describe Homebrew::Diagnostic::Checks do it "triggers when the CLT SDK version doesn't match the folder name" do allow_any_instance_of(OS::Mac::CLTSDKLocator).to receive(:all_sdks).and_return([ - OS::Mac::SDK.new(OS::Mac::Version.new("10.14"), "/some/path/MacOSX10.15.sdk", :clt), + OS::Mac::SDK.new(MacOSVersion.new("10.14"), "/some/path/MacOSX10.15.sdk", :clt), ]) expect(checks.check_broken_sdks) @@ -106,7 +106,7 @@ describe Homebrew::Diagnostic::Checks do it "triggers when the Xcode SDK version doesn't match the folder name" do allow(OS::Mac).to receive(:sdk_locator).and_return(OS::Mac::Xcode.sdk_locator) allow_any_instance_of(OS::Mac::XcodeSDKLocator).to receive(:all_sdks).and_return([ - OS::Mac::SDK.new(OS::Mac::Version.new("10.14"), "/some/path/MacOSX10.15.sdk", :xcode), + OS::Mac::SDK.new(MacOSVersion.new("10.14"), "/some/path/MacOSX10.15.sdk", :xcode), ]) expect(checks.check_broken_sdks) diff --git a/Library/Homebrew/test/os/mac/formula_spec.rb b/Library/Homebrew/test/os/mac/formula_spec.rb index 593c5fdebf..8a91e72e4a 100644 --- a/Library/Homebrew/test/os/mac/formula_spec.rb +++ b/Library/Homebrew/test/os/mac/formula_spec.rb @@ -7,7 +7,7 @@ describe Formula do describe "#uses_from_macos" do before do allow(OS).to receive(:mac?).and_return(true) - allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra)) + allow(OS::Mac).to receive(:version).and_return(MacOSVersion.from_symbol(:sierra)) end it "adds a macOS dependency to all specs if the OS version meets requirements" do diff --git a/Library/Homebrew/test/os/mac/sdk_spec.rb b/Library/Homebrew/test/os/mac/sdk_spec.rb index ad3c731d75..fd9b5e9ac0 100644 --- a/Library/Homebrew/test/os/mac/sdk_spec.rb +++ b/Library/Homebrew/test/os/mac/sdk_spec.rb @@ -3,15 +3,15 @@ describe OS::Mac::CLTSDKLocator do subject(:locator) { described_class.new } - let(:big_sur_sdk) { OS::Mac::SDK.new(OS::Mac::Version.new("11"), "/some/path/MacOSX.sdk", :clt) } - let(:catalina_sdk) { OS::Mac::SDK.new(OS::Mac::Version.new("10.15"), "/some/path/MacOSX10.15.sdk", :clt) } + let(:big_sur_sdk) { OS::Mac::SDK.new(MacOSVersion.new("11"), "/some/path/MacOSX.sdk", :clt) } + let(:catalina_sdk) { OS::Mac::SDK.new(MacOSVersion.new("10.15"), "/some/path/MacOSX10.15.sdk", :clt) } specify "#sdk_for" do allow(locator).to receive(:all_sdks).and_return([big_sur_sdk, catalina_sdk]) - expect(locator.sdk_for(OS::Mac::Version.new("11"))).to eq(big_sur_sdk) - expect(locator.sdk_for(OS::Mac::Version.new("10.15"))).to eq(catalina_sdk) - expect { locator.sdk_for(OS::Mac::Version.new("10.14")) }.to raise_error(described_class::NoSDKError) + expect(locator.sdk_for(MacOSVersion.new("11"))).to eq(big_sur_sdk) + expect(locator.sdk_for(MacOSVersion.new("10.15"))).to eq(catalina_sdk) + expect { locator.sdk_for(MacOSVersion.new("10.14")) }.to raise_error(described_class::NoSDKError) end describe "#sdk_if_applicable" do @@ -20,27 +20,27 @@ describe OS::Mac::CLTSDKLocator do end it "returns the requested SDK" do - expect(locator.sdk_if_applicable(OS::Mac::Version.new("11"))).to eq(big_sur_sdk) - expect(locator.sdk_if_applicable(OS::Mac::Version.new("10.15"))).to eq(catalina_sdk) + expect(locator.sdk_if_applicable(MacOSVersion.new("11"))).to eq(big_sur_sdk) + expect(locator.sdk_if_applicable(MacOSVersion.new("10.15"))).to eq(catalina_sdk) end it "returns the latest SDK if the requested version is not found" do - expect(locator.sdk_if_applicable(OS::Mac::Version.new("10.14"))).to eq(big_sur_sdk) - expect(locator.sdk_if_applicable(OS::Mac::Version.new("12"))).to eq(big_sur_sdk) + expect(locator.sdk_if_applicable(MacOSVersion.new("10.14"))).to eq(big_sur_sdk) + expect(locator.sdk_if_applicable(MacOSVersion.new("12"))).to eq(big_sur_sdk) end it "returns the SDK matching the OS version if no version is specified" do - allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.new("10.15")) + allow(OS::Mac).to receive(:version).and_return(MacOSVersion.new("10.15")) expect(locator.sdk_if_applicable).to eq(catalina_sdk) end it "returns the latest SDK on older OS versions when there's no matching SDK" do - allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.new("10.14")) + allow(OS::Mac).to receive(:version).and_return(MacOSVersion.new("10.14")) expect(locator.sdk_if_applicable).to eq(big_sur_sdk) end it "returns nil if the OS is newer than all SDKs" do - allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.new("12")) + allow(OS::Mac).to receive(:version).and_return(MacOSVersion.new("12")) expect(locator.sdk_if_applicable).to be_nil end end @@ -59,7 +59,7 @@ describe OS::Mac::CLTSDKLocator do sdk = sdks.first expect(sdk.path).to eq(big_sur_sdk_prefix/"MacOSX.sdk") - expect(sdk.version).to eq(OS::Mac::Version.new("11")) + expect(sdk.version).to eq(MacOSVersion.new("11")) expect(sdk.source).to eq(:clt) end @@ -71,7 +71,7 @@ describe OS::Mac::CLTSDKLocator do sdk = sdks.first expect(sdk.path).to eq(mojave_broken_sdk_prefix/"MacOSX10.14.sdk") - expect(sdk.version).to eq(OS::Mac::Version.new("10.15")) + expect(sdk.version).to eq(MacOSVersion.new("10.15")) expect(sdk.source).to eq(:clt) end @@ -83,7 +83,7 @@ describe OS::Mac::CLTSDKLocator do sdk = sdks.first expect(sdk.path).to eq(high_sierra_sdk_prefix/"MacOSX10.13.sdk") - expect(sdk.version).to eq(OS::Mac::Version.new("10.13")) + expect(sdk.version).to eq(MacOSVersion.new("10.13")) expect(sdk.source).to eq(:clt) end diff --git a/Library/Homebrew/test/os/os_spec.rb b/Library/Homebrew/test/os/os_spec.rb index 1e671f67a5..7dae2be4ce 100644 --- a/Library/Homebrew/test/os/os_spec.rb +++ b/Library/Homebrew/test/os/os_spec.rb @@ -1,9 +1,19 @@ # frozen_string_literal: true describe OS do - describe ".kernel_version" do - it "is not empty" do - expect(described_class.kernel_version).not_to be_empty + describe "::kernel_version" do + it "is not NULL" do + expect(described_class.kernel_version).not_to be_null + end + end + + describe "::kernel_name" do + it "returns Linux on Linux", :needs_linux do + expect(described_class.kernel_name).to eq "Linux" + end + + it "returns Darwin on macOS", :needs_macos do + expect(described_class.kernel_name).to eq "Darwin" end end end diff --git a/Library/Homebrew/test/software_spec_spec.rb b/Library/Homebrew/test/software_spec_spec.rb index 959627298a..dc93aa2ac6 100644 --- a/Library/Homebrew/test/software_spec_spec.rb +++ b/Library/Homebrew/test/software_spec_spec.rb @@ -176,7 +176,7 @@ describe SoftwareSpec do context "when running on macOS", :needs_macos do before do allow(OS).to receive(:mac?).and_return(true) - allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra)) + allow(OS::Mac).to receive(:version).and_return(MacOSVersion.from_symbol(:sierra)) end it "adds a macOS dependency if the OS version meets requirements" do @@ -212,7 +212,7 @@ describe SoftwareSpec do it "raises an error if passing invalid OS versions" do expect do spec.uses_from_macos("foo", since: :bar) - end.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar") + end.to raise_error(MacOSVersion::Error, "unknown or unsupported macOS version: :bar") end end end diff --git a/Library/Homebrew/test/test_runner_formula_spec.rb b/Library/Homebrew/test/test_runner_formula_spec.rb index 7b1667a917..30c7e5dd74 100644 --- a/Library/Homebrew/test/test_runner_formula_spec.rb +++ b/Library/Homebrew/test/test_runner_formula_spec.rb @@ -240,14 +240,14 @@ describe TestRunnerFormula do context "when a formula has a versioned MacOSRequirement" do context "when passed a compatible macOS version" do it "returns true" do - expect(described_class.new(needs_modern_compiler).compatible_with?(OS::Mac::Version.new("13"))) + expect(described_class.new(needs_modern_compiler).compatible_with?(MacOSVersion.new("13"))) .to be(true) end end context "when passed an incompatible macOS version" do it "returns false" do - expect(described_class.new(needs_modern_compiler).compatible_with?(OS::Mac::Version.new("11"))) + expect(described_class.new(needs_modern_compiler).compatible_with?(MacOSVersion.new("11"))) .to be(false) end end @@ -255,8 +255,8 @@ describe TestRunnerFormula do context "when a formula has an unversioned MacOSRequirement" do it "returns true" do - MacOSVersions::SYMBOLS.each_value do |v| - version = OS::Mac::Version.new(v) + MacOSVersion::SYMBOLS.each_value do |v| + version = MacOSVersion.new(v) expect(described_class.new(xcode_helper).compatible_with?(version)).to be(true) end end @@ -264,8 +264,8 @@ describe TestRunnerFormula do context "when a formula has no declared MacOSRequirement" do it "returns true" do - MacOSVersions::SYMBOLS.each_value do |v| - version = OS::Mac::Version.new(v) + MacOSVersion::SYMBOLS.each_value do |v| + version = MacOSVersion.new(v) expect(described_class.new(testball).compatible_with?(version)).to be(true) expect(described_class.new(linux_kernel_requirer).compatible_with?(version)).to be(true) expect(described_class.new(old_non_portable_software).compatible_with?(version)).to be(true) diff --git a/Library/Homebrew/test/utils/bottles/bottles_spec.rb b/Library/Homebrew/test/utils/bottles/bottles_spec.rb index fb492384f0..57adf15a2f 100644 --- a/Library/Homebrew/test/utils/bottles/bottles_spec.rb +++ b/Library/Homebrew/test/utils/bottles/bottles_spec.rb @@ -5,7 +5,7 @@ require "utils/bottles" describe Utils::Bottles do describe "#tag", :needs_macos do it "returns :big_sur or :arm64_big_sur on Big Sur" do - allow(MacOS).to receive(:version).and_return(MacOS::Version.new("11.0")) + allow(MacOS).to receive(:version).and_return(MacOSVersion.new("11.0")) if Hardware::CPU.intel? expect(described_class.tag).to eq(:big_sur) else diff --git a/Library/Homebrew/test/utils/bottles/tag_spec.rb b/Library/Homebrew/test/utils/bottles/tag_spec.rb index 1d6b60fd03..af9b78d735 100644 --- a/Library/Homebrew/test/utils/bottles/tag_spec.rb +++ b/Library/Homebrew/test/utils/bottles/tag_spec.rb @@ -8,7 +8,7 @@ describe Utils::Bottles::Tag do tag = described_class.from_symbol(symbol) expect(tag.system).to eq(:big_sur) expect(tag.arch).to eq(:arm64) - expect(tag.to_macos_version).to eq(OS::Mac::Version.from_symbol(:big_sur)) + expect(tag.to_macos_version).to eq(MacOSVersion.from_symbol(:big_sur)) expect(tag.macos?).to be true expect(tag.linux?).to be false expect(tag.to_sym).to eq(symbol) @@ -19,7 +19,7 @@ describe Utils::Bottles::Tag do tag = described_class.from_symbol(symbol) expect(tag.system).to eq(:big_sur) expect(tag.arch).to eq(:x86_64) - expect(tag.to_macos_version).to eq(OS::Mac::Version.from_symbol(:big_sur)) + expect(tag.to_macos_version).to eq(MacOSVersion.from_symbol(:big_sur)) expect(tag.macos?).to be true expect(tag.linux?).to be false expect(tag.to_sym).to eq(symbol) @@ -30,7 +30,7 @@ describe Utils::Bottles::Tag do tag = described_class.from_symbol(symbol) expect(tag.system).to eq(:linux) expect(tag.arch).to eq(:x86_64) - expect { tag.to_macos_version }.to raise_error(MacOSVersionError) + expect { tag.to_macos_version }.to raise_error(MacOSVersion::Error) expect(tag.macos?).to be false expect(tag.linux?).to be true expect(tag.to_sym).to eq(symbol) diff --git a/Library/Homebrew/test/version_spec.rb b/Library/Homebrew/test/version_spec.rb index ec55cc35bf..f7001ed6b3 100644 --- a/Library/Homebrew/test/version_spec.rb +++ b/Library/Homebrew/test/version_spec.rb @@ -240,16 +240,6 @@ describe Version do expect(versions.sort_by { |v| described_class.create(v) }).to eq(versions) end - describe "#empty?" do - it "returns true if version is empty" do - expect(described_class.create("").empty?).to be(true) - end - - it "returns false if version is not empty" do - expect(described_class.create("1.2.3").empty?).to be(false) - end - end - specify "hash equality" do v1 = described_class.create("0.1.0") v2 = described_class.create("0.1.0") diff --git a/Library/Homebrew/test_runner_formula.rb b/Library/Homebrew/test_runner_formula.rb index 163e30dc7d..e0da75f3f4 100644 --- a/Library/Homebrew/test_runner_formula.rb +++ b/Library/Homebrew/test_runner_formula.rb @@ -68,7 +68,7 @@ class TestRunnerFormula formula.requirements.find { |r| r.is_a?(MacOSRequirement) && r.version_specified? } end - sig { params(macos_version: OS::Mac::Version).returns(T::Boolean) } + sig { params(macos_version: MacOSVersion).returns(T::Boolean) } def compatible_with?(macos_version) # Assign to a variable to assist type-checking. requirement = versioned_macos_requirement diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index 1ef0334cea..233a7aa80b 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -189,9 +189,9 @@ module Utils to_sym.to_s end - sig { returns(OS::Mac::Version) } + sig { returns(MacOSVersion) } def to_macos_version - @to_macos_version ||= OS::Mac::Version.from_symbol(system) + @to_macos_version ||= MacOSVersion.from_symbol(system) end sig { returns(T::Boolean) } @@ -203,7 +203,7 @@ module Utils def macos? to_macos_version true - rescue MacOSVersionError + rescue MacOSVersion::Error false end diff --git a/Library/Homebrew/version.rb b/Library/Homebrew/version.rb index af12755d83..9cf2fbcc54 100644 --- a/Library/Homebrew/version.rb +++ b/Library/Homebrew/version.rb @@ -2,8 +2,6 @@ # frozen_string_literal: true require "pkg_version" -require "version/head" -require "version/null" require "version/parser" # A formula's version. @@ -345,35 +343,23 @@ class Version 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 + # odeprecate "Version.create", "Version.new" + 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 @@ -508,7 +494,10 @@ class Version def initialize(val, detected_from_url: false) raise TypeError, "Version value must be a string; got a #{val.class} (#{val})" unless val.respond_to?(:to_str) - @version = val.to_str + version = val.to_str + raise ArgumentError, "Version must not be empty" if version.blank? + + @version = version @detected_from_url = detected_from_url end @@ -517,14 +506,36 @@ class Version @detected_from_url end + HEAD_VERSION_REGEX = /\AHEAD(?:-(?.*))?\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 +553,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 +627,59 @@ 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(".")) - end + return self if null? - sig { returns(T::Boolean) } - def empty? - version.empty? + major_minor_patch = T.must(tokens[0..2]) + major_minor_patch.empty? ? NULL : self.class.new(major_minor_patch.join(".")) end sig { returns(Integer) } @@ -629,6 +689,8 @@ class Version sig { returns(Float) } def to_f + return Float::NAN if null? + version.to_f end @@ -639,10 +701,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 "#" if null? + + super + end + sig { returns(T.self_type) } def freeze tokens # Determine and store tokens before freezing @@ -651,12 +720,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 +735,7 @@ 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. + # NOTE: Constructor needs to called with an arbitrary non-empty version which is then set to `nil`. + NULL = Version.new("NULL").tap { |v| v.instance_variable_set(:@version, nil) }.freeze end diff --git a/Library/Homebrew/version/head.rb b/Library/Homebrew/version/head.rb deleted file mode 100644 index 0edeb47470..0000000000 --- a/Library/Homebrew/version/head.rb +++ /dev/null @@ -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 diff --git a/Library/Homebrew/version/null.rb b/Library/Homebrew/version/null.rb deleted file mode 100644 index 80fa6f686c..0000000000 --- a/Library/Homebrew/version/null.rb +++ /dev/null @@ -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 - "#" - end - end - private_constant :NullVersion - - # Represents the absence of a version. - NULL = NullVersion.instance.freeze -end