| 
									
										
										
										
											2024-08-12 10:30:59 +01:00
										 |  |  | # typed: true # rubocop:todo Sorbet/StrictSigil | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "version" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # A macOS version. | 
					
						
							|  |  |  | 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 = { | 
					
						
							| 
									
										
										
										
											2024-06-10 18:56:50 +01:00
										 |  |  |     sequoia:     "15", | 
					
						
							| 
									
										
										
										
											2023-06-05 18:36:03 +01:00
										 |  |  |     sonoma:      "14", | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-31 14:57:02 +08:00
										 |  |  |   sig { params(macos_version: MacOSVersion).returns(Version) } | 
					
						
							|  |  |  |   def self.kernel_major_version(macos_version) | 
					
						
							|  |  |  |     version_major = macos_version.major.to_i | 
					
						
							|  |  |  |     if version_major > 10
 | 
					
						
							|  |  |  |       Version.new((version_major + 9).to_s) | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       version_minor = macos_version.minor.to_i | 
					
						
							|  |  |  |       Version.new((version_minor + 4).to_s) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2024-10-31 02:39:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 08:55:58 -08:00
										 |  |  |     super(T.must(version)) | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-03 12:33:00 -04:00
										 |  |  |   sig { returns(String) } | 
					
						
							|  |  |  |   def inspect | 
					
						
							|  |  |  |     "#<#{self.class.name}: #{to_s.inspect}>" | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |   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. | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |   # | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |   # 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 |