2025-04-05 16:03:18 -04:00
|
|
|
# typed: strict
|
2022-06-23 17:18:58 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2025-04-11 16:42:31 -04:00
|
|
|
require "requirements/macos_requirement"
|
2022-06-28 15:04:30 -04:00
|
|
|
require "simulate_system"
|
2022-06-23 17:18:58 -04:00
|
|
|
|
|
|
|
module OnSystem
|
2025-04-05 16:03:18 -04:00
|
|
|
ARCH_OPTIONS = T.let([:intel, :arm].freeze, T::Array[Symbol])
|
|
|
|
BASE_OS_OPTIONS = T.let([:macos, :linux].freeze, T::Array[Symbol])
|
|
|
|
ALL_OS_OPTIONS = T.let([*MacOSVersion::SYMBOLS.keys, :linux].freeze, T::Array[Symbol])
|
|
|
|
ALL_OS_ARCH_COMBINATIONS = T.let(
|
|
|
|
ALL_OS_OPTIONS.product(ARCH_OPTIONS).freeze,
|
|
|
|
T::Array[[Symbol, Symbol]],
|
|
|
|
)
|
|
|
|
|
|
|
|
VALID_OS_ARCH_TAGS = T.let(
|
|
|
|
ALL_OS_ARCH_COMBINATIONS.filter_map do |os, arch|
|
|
|
|
tag = Utils::Bottles::Tag.new(system: os, arch:)
|
|
|
|
next unless tag.valid_combination?
|
|
|
|
|
|
|
|
tag
|
|
|
|
end.freeze,
|
|
|
|
T::Array[Utils::Bottles::Tag],
|
|
|
|
)
|
2025-06-03 11:57:17 -04:00
|
|
|
|
2025-04-07 12:38:50 -04:00
|
|
|
class UsesOnSystem < T::Struct
|
|
|
|
prop :arm, T::Boolean, default: false
|
|
|
|
prop :intel, T::Boolean, default: false
|
|
|
|
prop :linux, T::Boolean, default: false
|
|
|
|
prop :macos, T::Boolean, default: false
|
2025-04-11 16:42:31 -04:00
|
|
|
prop :macos_requirements, T::Set[MacOSRequirement], default: Set[]
|
2025-04-07 12:38:50 -04:00
|
|
|
|
|
|
|
alias arm? arm
|
|
|
|
alias intel? intel
|
|
|
|
alias linux? linux
|
|
|
|
alias macos? macos
|
|
|
|
|
|
|
|
# Whether the object has only default values.
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def empty?
|
2025-04-11 16:42:31 -04:00
|
|
|
!@arm && !@intel && !@linux && !@macos && @macos_requirements.empty?
|
2025-04-07 12:38:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Whether the object has any non-default values.
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def present? = !empty?
|
|
|
|
end
|
|
|
|
|
2025-04-11 16:42:31 -04:00
|
|
|
# Converts an `or_condition` value to a suitable `MacOSRequirements`
|
|
|
|
# `comparator` string, defaulting to `==` if the provided argument is `nil`.
|
|
|
|
sig { params(symbol: T.nilable(Symbol)).returns(String) }
|
|
|
|
def self.comparator_from_or_condition(symbol)
|
|
|
|
case symbol
|
|
|
|
when :or_newer
|
|
|
|
">="
|
|
|
|
when :or_older
|
|
|
|
"<="
|
|
|
|
else
|
|
|
|
"=="
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-23 17:18:58 -04:00
|
|
|
sig { params(arch: Symbol).returns(T::Boolean) }
|
2023-03-19 19:37:28 -07:00
|
|
|
def self.arch_condition_met?(arch)
|
2022-06-28 15:04:30 -04:00
|
|
|
raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch)
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2022-07-23 02:00:28 +02:00
|
|
|
arch == Homebrew::SimulateSystem.current_arch
|
2022-06-23 17:18:58 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) }
|
2023-03-19 19:37:28 -07:00
|
|
|
def self.os_condition_met?(os_name, or_condition = nil)
|
2023-12-18 09:34:01 -08:00
|
|
|
return Homebrew::SimulateSystem.send(:"simulating_or_running_on_#{os_name}?") if BASE_OS_OPTIONS.include?(os_name)
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2023-05-09 02:15:28 +02:00
|
|
|
raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersion::SYMBOLS.key?(os_name)
|
2022-06-23 17:18:58 -04:00
|
|
|
|
|
|
|
if or_condition.present? && [:or_newer, :or_older].exclude?(or_condition)
|
|
|
|
raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}"
|
|
|
|
end
|
|
|
|
|
2022-07-28 09:18:16 -04:00
|
|
|
return false if Homebrew::SimulateSystem.simulating_or_running_on_linux?
|
2022-07-05 19:05:42 -04:00
|
|
|
|
2023-05-09 02:15:28 +02:00
|
|
|
base_os = MacOSVersion.from_symbol(os_name)
|
2022-07-31 20:42:32 -04:00
|
|
|
current_os = if Homebrew::SimulateSystem.current_os == :macos
|
2022-08-03 01:32:37 -04:00
|
|
|
# Assume the oldest macOS version when simulating a generic macOS version
|
|
|
|
# Version::NULL is always treated as less than any other version.
|
2022-07-31 20:42:32 -04:00
|
|
|
Version::NULL
|
|
|
|
else
|
2023-05-09 02:15:28 +02:00
|
|
|
MacOSVersion.from_symbol(Homebrew::SimulateSystem.current_os)
|
2022-07-31 20:42:32 -04:00
|
|
|
end
|
2022-06-23 17:18:58 -04:00
|
|
|
|
|
|
|
return current_os >= base_os if or_condition == :or_newer
|
|
|
|
return current_os <= base_os if or_condition == :or_older
|
|
|
|
|
|
|
|
current_os == base_os
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(method_name: Symbol).returns(Symbol) }
|
2023-03-19 19:37:28 -07:00
|
|
|
def self.condition_from_method_name(method_name)
|
2022-06-23 17:18:58 -04:00
|
|
|
method_name.to_s.sub(/^on_/, "").to_sym
|
|
|
|
end
|
|
|
|
|
2025-04-05 16:03:18 -04:00
|
|
|
sig { params(base: T::Class[T.anything]).void }
|
2023-03-19 19:37:28 -07:00
|
|
|
def self.setup_arch_methods(base)
|
2022-06-23 17:18:58 -04:00
|
|
|
ARCH_OPTIONS.each do |arch|
|
2023-12-18 09:34:01 -08:00
|
|
|
base.define_method(:"on_#{arch}") do |&block|
|
2025-04-07 12:38:50 -04:00
|
|
|
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
|
|
|
|
@uses_on_system.send(:"#{arch}=", true)
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2023-03-19 19:37:28 -07:00
|
|
|
return unless OnSystem.arch_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2025-04-05 16:03:18 -04:00
|
|
|
@called_in_on_system_block = T.let(true, T.nilable(T::Boolean))
|
2022-06-23 17:18:58 -04:00
|
|
|
result = block.call
|
|
|
|
@called_in_on_system_block = false
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
end
|
2022-08-09 11:34:52 -04:00
|
|
|
|
2022-08-10 17:15:37 -04:00
|
|
|
base.define_method(:on_arch_conditional) do |arm: nil, intel: nil|
|
2025-04-07 12:38:50 -04:00
|
|
|
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
|
|
|
|
@uses_on_system.arm = true if arm
|
|
|
|
@uses_on_system.intel = true if intel
|
2022-08-09 11:34:52 -04:00
|
|
|
|
2023-12-14 02:52:30 +00:00
|
|
|
if OnSystem.arch_condition_met? :arm
|
|
|
|
arm
|
|
|
|
elsif OnSystem.arch_condition_met? :intel
|
|
|
|
intel
|
|
|
|
end
|
2022-08-09 11:34:52 -04:00
|
|
|
end
|
2022-06-29 17:48:21 -04:00
|
|
|
end
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2025-04-05 16:03:18 -04:00
|
|
|
sig { params(base: T::Class[T.anything]).void }
|
2023-03-19 19:37:28 -07:00
|
|
|
def self.setup_base_os_methods(base)
|
2022-06-29 11:38:55 -04:00
|
|
|
BASE_OS_OPTIONS.each do |base_os|
|
2023-12-18 09:34:01 -08:00
|
|
|
base.define_method(:"on_#{base_os}") do |&block|
|
2025-04-07 12:38:50 -04:00
|
|
|
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
|
|
|
|
@uses_on_system.send(:"#{base_os}=", true)
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2023-03-19 19:37:28 -07:00
|
|
|
return unless OnSystem.os_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2022-06-29 11:38:55 -04:00
|
|
|
@called_in_on_system_block = true
|
|
|
|
result = block.call
|
|
|
|
@called_in_on_system_block = false
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2022-06-29 11:38:55 -04:00
|
|
|
result
|
2022-06-23 17:18:58 -04:00
|
|
|
end
|
|
|
|
end
|
2022-07-08 02:44:48 -04:00
|
|
|
|
|
|
|
base.define_method(:on_system) do |linux, macos:, &block|
|
2025-04-07 12:38:50 -04:00
|
|
|
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
|
|
|
|
@uses_on_system.linux = true
|
|
|
|
@uses_on_system.macos = true
|
2022-07-08 02:44:48 -04:00
|
|
|
|
2022-07-11 04:03:37 -04:00
|
|
|
raise ArgumentError, "The first argument to `on_system` must be `:linux`" if linux != :linux
|
2022-07-08 02:44:48 -04:00
|
|
|
|
|
|
|
os_version, or_condition = if macos.to_s.include?("_or_")
|
|
|
|
macos.to_s.split(/_(?=or_)/).map(&:to_sym)
|
|
|
|
else
|
|
|
|
[macos.to_sym, nil]
|
|
|
|
end
|
2025-04-11 16:42:31 -04:00
|
|
|
|
|
|
|
comparator = OnSystem.comparator_from_or_condition(or_condition)
|
|
|
|
@uses_on_system.macos_requirements << MacOSRequirement.new([os_version], comparator:)
|
2022-07-08 02:44:48 -04:00
|
|
|
return if !OnSystem.os_condition_met?(os_version, or_condition) && !OnSystem.os_condition_met?(:linux)
|
|
|
|
|
|
|
|
@called_in_on_system_block = true
|
|
|
|
result = block.call
|
|
|
|
@called_in_on_system_block = false
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
2023-01-13 14:40:03 +01:00
|
|
|
|
|
|
|
base.define_method(:on_system_conditional) do |macos: nil, linux: nil|
|
2025-04-07 12:38:50 -04:00
|
|
|
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
|
|
|
|
@uses_on_system.macos = true if macos
|
|
|
|
@uses_on_system.linux = true if linux
|
2023-01-13 14:40:03 +01:00
|
|
|
|
2023-12-14 02:52:30 +00:00
|
|
|
if OnSystem.os_condition_met?(:macos) && macos.present?
|
|
|
|
macos
|
|
|
|
elsif OnSystem.os_condition_met?(:linux) && linux.present?
|
|
|
|
linux
|
|
|
|
end
|
2023-01-13 14:40:03 +01:00
|
|
|
end
|
2022-06-29 17:48:21 -04:00
|
|
|
end
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2025-04-05 16:03:18 -04:00
|
|
|
sig { params(base: T::Class[T.anything]).void }
|
2023-03-19 19:37:28 -07:00
|
|
|
def self.setup_macos_methods(base)
|
2023-05-09 02:15:28 +02:00
|
|
|
MacOSVersion::SYMBOLS.each_key do |os_name|
|
2023-12-18 09:34:01 -08:00
|
|
|
base.define_method(:"on_#{os_name}") do |or_condition = nil, &block|
|
2025-04-07 12:38:50 -04:00
|
|
|
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
|
|
|
|
@uses_on_system.macos = true
|
2022-06-23 17:18:58 -04:00
|
|
|
|
2023-03-19 19:37:28 -07:00
|
|
|
os_condition = OnSystem.condition_from_method_name T.must(__method__)
|
2025-04-11 16:42:31 -04:00
|
|
|
comparator = OnSystem.comparator_from_or_condition(or_condition)
|
|
|
|
@uses_on_system.macos_requirements << MacOSRequirement.new([os_condition], comparator:)
|
|
|
|
|
2022-06-23 17:18:58 -04:00
|
|
|
return unless OnSystem.os_condition_met? os_condition, or_condition
|
|
|
|
|
2025-04-05 16:03:18 -04:00
|
|
|
@on_system_block_min_os = T.let(
|
|
|
|
if or_condition == :or_older
|
|
|
|
@called_in_on_system_block ? @on_system_block_min_os : MacOSVersion.new(HOMEBREW_MACOS_OLDEST_ALLOWED)
|
|
|
|
else
|
|
|
|
MacOSVersion.from_symbol(os_condition)
|
|
|
|
end,
|
|
|
|
T.nilable(MacOSVersion),
|
|
|
|
)
|
2022-06-23 17:18:58 -04:00
|
|
|
@called_in_on_system_block = true
|
|
|
|
result = block.call
|
|
|
|
@called_in_on_system_block = false
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-06-29 17:48:21 -04:00
|
|
|
|
2025-04-05 16:03:18 -04:00
|
|
|
sig { params(_base: T::Class[T.anything]).void }
|
2022-06-29 17:48:21 -04:00
|
|
|
def self.included(_base)
|
|
|
|
raise "Do not include `OnSystem` directly. Instead, include `OnSystem::MacOSAndLinux` or `OnSystem::MacOSOnly`"
|
|
|
|
end
|
|
|
|
|
|
|
|
module MacOSAndLinux
|
2025-04-05 16:03:18 -04:00
|
|
|
sig { params(base: T::Class[T.anything]).void }
|
2022-06-29 17:48:21 -04:00
|
|
|
def self.included(base)
|
|
|
|
OnSystem.setup_arch_methods(base)
|
|
|
|
OnSystem.setup_base_os_methods(base)
|
|
|
|
OnSystem.setup_macos_methods(base)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module MacOSOnly
|
2025-04-05 16:03:18 -04:00
|
|
|
sig { params(base: T::Class[T.anything]).void }
|
2022-06-29 17:48:21 -04:00
|
|
|
def self.included(base)
|
|
|
|
OnSystem.setup_arch_methods(base)
|
|
|
|
OnSystem.setup_macos_methods(base)
|
|
|
|
end
|
|
|
|
end
|
2022-06-23 17:18:58 -04:00
|
|
|
end
|