Skip to content

Commit 3df8f70

Browse files
committed
OnSystem: Add UsesOnSystem class
This adds a `UsesOnSystem` class to `OnSystem`, containing boolean instance variables to indicate which types of on_system methods are used in a formula or cask. This is intended as a replacement for `@on_system_blocks_exist`, which doesn't allow us to determine what kinds of on_system calls were used. This provides more granularity but we can still use `@uses_on_system.present?` to determine whether any on_system calls were used (and this doubles as a `nil` check in `Formula`, as the `self.class` instance variable has to use a nilable type). The `UsesOnSystem` instance variables cover the current `ARCH_OPTIONS` and `BASE_OS_OPTIONS`. At the moment, we mostly need to tell whether there are macOS/Linux or Intel/ARM on_system calls, so I've omitted instance variables for specific macOS version until we have a need for them. As a practical example, if you wanted to determine whether a cask uses Linux on_system calls, you can call `cask.uses_on_system.linux?`. The `linux` boolean will be `true` if the cask has an `on_linux` block, an `on_system` block (which requires Linux), or uses `os linux: ...`. This is something that would be challenging to determine from outside of `OnSystem` but it's relatively easy to collect the information in `OnSystem` methods and make it available like this.
1 parent bafa2ec commit 3df8f70

24 files changed

+720
-36
lines changed

Library/Homebrew/cask/audit.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ def audit_min_os
718718
cask_min_os = [on_system_block_min_os, cask.depends_on.macos&.minimum_version].compact.max
719719
odebug "Declared minimum OS version: #{cask_min_os&.to_sym}"
720720
return if cask_min_os&.to_sym == min_os.to_sym
721-
return if cask.on_system_blocks_exist? &&
721+
return if cask.uses_on_system.present? &&
722722
OnSystem.arch_condition_met?(:arm) &&
723723
cask_min_os.present? &&
724724
cask_min_os < MacOSVersion.new("11")

Library/Homebrew/cask/cask.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def to_hash_with_variations
414414
hash = to_h
415415
variations = {}
416416

417-
if @dsl.on_system_blocks_exist?
417+
if @dsl.uses_on_system.present?
418418
begin
419419
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
420420
next if bottle_tag.linux? && @dsl.os.nil?

Library/Homebrew/cask/dsl.rb

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ class DSL
106106
:no_autobump!,
107107
:autobump?,
108108
:no_autobump_message,
109-
:on_system_blocks_exist?,
110-
:on_system_block_min_os,
111109
:depends_on_set_in_block?,
110+
:on_system_block_min_os,
111+
:uses_on_system,
112112
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
113113
*ACTIVATABLE_ARTIFACT_CLASSES.map(&:dsl_key),
114114
*ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
@@ -121,6 +121,11 @@ class DSL
121121
:disable_date, :disable_reason, :disable_replacement_cask,
122122
:disable_replacement_formula, :on_system_block_min_os
123123

124+
# A `UsesOnSystem` object that contains boolean instance variables
125+
# indicating whether the cask uses specific on_system methods.
126+
sig { returns(OnSystem::UsesOnSystem) }
127+
attr_reader :uses_on_system
128+
124129
sig { params(cask: Cask).void }
125130
def initialize(cask)
126131
# NOTE: Variables set by `set_unique_stanza` must be initialized to `nil`.
@@ -153,13 +158,13 @@ def initialize(cask)
153158
@name = T.let([], T::Array[String])
154159
@autobump = T.let(true, T::Boolean)
155160
@no_autobump_defined = T.let(false, T::Boolean)
156-
@on_system_blocks_exist = T.let(false, T::Boolean)
157161
@os = T.let(nil, T.nilable(String))
158162
@on_system_block_min_os = T.let(nil, T.nilable(MacOSVersion))
159163
@sha256 = T.let(nil, T.nilable(T.any(Checksum, Symbol)))
160164
@staged_path = T.let(nil, T.nilable(Pathname))
161165
@token = T.let(cask.token, String)
162166
@url = T.let(nil, T.nilable(URL))
167+
@uses_on_system = T.let(OnSystem::UsesOnSystem.new, OnSystem::UsesOnSystem)
163168
@version = T.let(nil, T.nilable(DSL::Version))
164169
end
165170

@@ -175,9 +180,6 @@ def disabled? = @disabled
175180
sig { returns(T::Boolean) }
176181
def livecheck_defined? = @livecheck_defined
177182

178-
sig { returns(T::Boolean) }
179-
def on_system_blocks_exist? = @on_system_blocks_exist
180-
181183
# Specifies the cask's name.
182184
#
183185
# NOTE: Multiple names can be specified.
@@ -392,8 +394,15 @@ def sha256(arg = nil, arm: nil, intel: nil, x86_64: nil, x86_64_linux: nil, arm6
392394

393395
x86_64 ||= intel if intel.present? && x86_64.nil?
394396
set_unique_stanza(:sha256, should_return) do
395-
if arm.present? || x86_64.present? || x86_64_linux.present? || arm64_linux.present?
396-
@on_system_blocks_exist = true
397+
@uses_on_system.arm = true if arm.present?
398+
@uses_on_system.intel = true if x86_64.present?
399+
if x86_64_linux.present?
400+
@uses_on_system.intel = true
401+
@uses_on_system.linux = true
402+
end
403+
if arm64_linux.present?
404+
@uses_on_system.arm = true
405+
@uses_on_system.linux = true
397406
end
398407

399408
val = arg || on_system_conditional(
@@ -424,7 +433,8 @@ def arch(arm: nil, intel: nil)
424433
should_return = arm.nil? && intel.nil?
425434

426435
set_unique_stanza(:arch, should_return) do
427-
@on_system_blocks_exist = true
436+
@uses_on_system.arm = true if arm
437+
@uses_on_system.intel = true if intel
428438

429439
on_arch_conditional(arm:, intel:)
430440
end
@@ -449,7 +459,8 @@ def os(macos: nil, linux: nil)
449459
should_return = macos.nil? && linux.nil?
450460

451461
set_unique_stanza(:os, should_return) do
452-
@on_system_blocks_exist = true
462+
@uses_on_system.macos = true if macos
463+
@uses_on_system.linux = true if linux
453464

454465
on_system_conditional(macos:, linux:)
455466
end

Library/Homebrew/dev-cmd/bump-cask-pr.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def generate_system_options(cask)
199199
# to on_system blocks referencing macOS versions.
200200
os_values = []
201201
arch_values = depends_on_archs.presence || []
202-
if cask.on_system_blocks_exist?
202+
if cask.uses_on_system.present?
203203
OnSystem::BASE_OS_OPTIONS.each do |os|
204204
os_values << if os == :macos
205205
(current_os_is_macos ? current_os : newest_macos)
@@ -235,7 +235,7 @@ def replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs)
235235
old_cask = begin
236236
Cask::CaskLoader.load(cask.sourcefile_path)
237237
rescue Cask::CaskInvalidError, Cask::CaskUnreadableError
238-
raise unless cask.on_system_blocks_exist?
238+
raise unless cask.uses_on_system.present?
239239
end
240240
next if old_cask.nil?
241241

@@ -262,7 +262,7 @@ def replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs)
262262
replacement_pairs << [/"#{old_hash}"/, ":no_check"] if old_hash != :no_check
263263
elsif old_hash == :no_check && new_hash != :no_check
264264
replacement_pairs << [":no_check", "\"#{new_hash}\""] if new_hash.is_a?(String)
265-
elsif new_hash && !cask.on_system_blocks_exist? && cask.languages.empty?
265+
elsif new_hash && cask.uses_on_system.blank? && cask.languages.empty?
266266
replacement_pairs << [old_hash.to_s, new_hash.to_s]
267267
elsif old_hash != :no_check
268268
opoo "Multiple checksum replacements required; ignoring specified `--sha256` argument." if new_hash

Library/Homebrew/dev-cmd/bump.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def retrieve_pull_requests(formula_or_cask, name, version: nil)
305305
).returns(VersionBumpInfo)
306306
}
307307
def retrieve_versions_by_arch(formula_or_cask:, repositories:, name:)
308-
is_cask_with_blocks = formula_or_cask.is_a?(Cask::Cask) && formula_or_cask.on_system_blocks_exist?
308+
is_cask_with_blocks = formula_or_cask.is_a?(Cask::Cask) && formula_or_cask.uses_on_system.present?
309309
type, version_name = if formula_or_cask.is_a?(Formula)
310310
[:formula, "formula version:"]
311311
else

Library/Homebrew/extend/on_system.rb

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,28 @@ module OnSystem
2222
T::Array[Utils::Bottles::Tag],
2323
)
2424

25+
class UsesOnSystem < T::Struct
26+
prop :arm, T::Boolean, default: false
27+
prop :intel, T::Boolean, default: false
28+
prop :linux, T::Boolean, default: false
29+
prop :macos, T::Boolean, default: false
30+
31+
alias arm? arm
32+
alias intel? intel
33+
alias linux? linux
34+
alias macos? macos
35+
36+
# Whether the object has only default values.
37+
sig { returns(T::Boolean) }
38+
def empty?
39+
!@arm && !@intel && !@linux && !@macos
40+
end
41+
42+
# Whether the object has any non-default values.
43+
sig { returns(T::Boolean) }
44+
def present? = !empty?
45+
end
46+
2547
sig { params(arch: Symbol).returns(T::Boolean) }
2648
def self.arch_condition_met?(arch)
2749
raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch)
@@ -65,7 +87,8 @@ def self.condition_from_method_name(method_name)
6587
def self.setup_arch_methods(base)
6688
ARCH_OPTIONS.each do |arch|
6789
base.define_method(:"on_#{arch}") do |&block|
68-
@on_system_blocks_exist = T.let(true, T.nilable(T::Boolean))
90+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
91+
@uses_on_system.send(:"#{arch}=", true)
6992

7093
return unless OnSystem.arch_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
7194

@@ -78,7 +101,9 @@ def self.setup_arch_methods(base)
78101
end
79102

80103
base.define_method(:on_arch_conditional) do |arm: nil, intel: nil|
81-
@on_system_blocks_exist = true
104+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
105+
@uses_on_system.arm = true if arm
106+
@uses_on_system.intel = true if intel
82107

83108
if OnSystem.arch_condition_met? :arm
84109
arm
@@ -92,7 +117,8 @@ def self.setup_arch_methods(base)
92117
def self.setup_base_os_methods(base)
93118
BASE_OS_OPTIONS.each do |base_os|
94119
base.define_method(:"on_#{base_os}") do |&block|
95-
@on_system_blocks_exist = true
120+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
121+
@uses_on_system.send(:"#{base_os}=", true)
96122

97123
return unless OnSystem.os_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
98124

@@ -105,7 +131,9 @@ def self.setup_base_os_methods(base)
105131
end
106132

107133
base.define_method(:on_system) do |linux, macos:, &block|
108-
@on_system_blocks_exist = true
134+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
135+
@uses_on_system.linux = true
136+
@uses_on_system.macos = true
109137

110138
raise ArgumentError, "The first argument to `on_system` must be `:linux`" if linux != :linux
111139

@@ -124,7 +152,9 @@ def self.setup_base_os_methods(base)
124152
end
125153

126154
base.define_method(:on_system_conditional) do |macos: nil, linux: nil|
127-
@on_system_blocks_exist = true
155+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
156+
@uses_on_system.macos = true if macos
157+
@uses_on_system.linux = true if linux
128158

129159
if OnSystem.os_condition_met?(:macos) && macos.present?
130160
macos
@@ -138,7 +168,8 @@ def self.setup_base_os_methods(base)
138168
def self.setup_macos_methods(base)
139169
MacOSVersion::SYMBOLS.each_key do |os_name|
140170
base.define_method(:"on_#{os_name}") do |or_condition = nil, &block|
141-
@on_system_blocks_exist = true
171+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
172+
@uses_on_system.macos = true
142173

143174
os_condition = OnSystem.condition_from_method_name T.must(__method__)
144175
return unless OnSystem.os_condition_met? os_condition, or_condition

Library/Homebrew/formula.rb

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ def initialize(name, path, spec, alias_path: nil, tap: nil, force_bottle: false)
270270
@follow_installed_alias = T.let(true, T::Boolean)
271271
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
272272
@oldname_locks = T.let([], T::Array[FormulaLock])
273-
@on_system_blocks_exist = T.let(false, T::Boolean)
273+
@uses_on_system = T.let(OnSystem::UsesOnSystem.new, OnSystem::UsesOnSystem)
274274
end
275275

276276
sig { params(spec_sym: Symbol).void }
@@ -2591,7 +2591,7 @@ def to_hash_with_variations
25912591

25922592
variations = {}
25932593

2594-
if path.exist? && on_system_blocks_exist?
2594+
if path.exist? && uses_on_system.present?
25952595
formula_contents = path.read
25962596
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
25972597
Homebrew::SimulateSystem.with_tag(bottle_tag) do
@@ -2789,9 +2789,11 @@ def internal_dependencies_hash(spec_symbol)
27892789
end
27902790
end
27912791

2792-
sig { returns(T.nilable(T::Boolean)) }
2793-
def on_system_blocks_exist?
2794-
self.class.on_system_blocks_exist? || @on_system_blocks_exist
2792+
# A `UsesOnSystem` object that contains boolean instance variables indicating
2793+
# whether the formula uses specific on_system methods.
2794+
sig { returns(OnSystem::UsesOnSystem) }
2795+
def uses_on_system
2796+
self.class.uses_on_system || @uses_on_system
27952797
end
27962798

27972799
sig {
@@ -3331,7 +3333,7 @@ def inherited(child)
33313333
@skip_clean_paths = T.let(Set.new, T.nilable(T::Set[T.any(String, Symbol)]))
33323334
@link_overwrite_paths = T.let(Set.new, T.nilable(T::Set[String]))
33333335
@loaded_from_api = T.let(false, T.nilable(T::Boolean))
3334-
@on_system_blocks_exist = T.let(false, T.nilable(T::Boolean))
3336+
@uses_on_system = T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
33353337
@network_access_allowed = T.let(SUPPORTED_NETWORK_ACCESS_PHASES.to_h do |phase|
33363338
[phase, DEFAULT_NETWORK_ACCESS_ALLOWED]
33373339
end, T.nilable(T::Hash[Symbol, T::Boolean]))
@@ -3345,6 +3347,7 @@ def freeze
33453347
@conflicts.freeze
33463348
@skip_clean_paths.freeze
33473349
@link_overwrite_paths.freeze
3350+
@uses_on_system.freeze
33483351
super
33493352
end
33503353

@@ -3355,10 +3358,10 @@ def network_access_allowed = T.must(@network_access_allowed)
33553358
sig { returns(T::Boolean) }
33563359
def loaded_from_api? = !!@loaded_from_api
33573360

3358-
# Whether this formula contains OS/arch-specific blocks
3359-
# (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`).
3360-
sig { returns(T::Boolean) }
3361-
def on_system_blocks_exist? = !!@on_system_blocks_exist
3361+
# A `UsesOnSystem` object that contains boolean instance variables
3362+
# indicating whether the formula uses specific on_system methods.
3363+
sig { returns(T.nilable(OnSystem::UsesOnSystem)) }
3364+
attr_reader :uses_on_system
33623365

33633366
# The reason for why this software is not linked (by default) to {::HOMEBREW_PREFIX}.
33643367
sig { returns(T.nilable(KegOnlyReason)) }

Library/Homebrew/readall.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def self.valid_formulae?(tap, bottle_tag: nil)
6666
readall_formula = readall_formula_class.new(formula_name, file, :stable, tap:)
6767
readall_formula.to_hash
6868
# TODO: Remove check for MACOS_MODULE_REGEX once the `MacOS` module is undefined on Linux
69-
cache[:valid_formulae][file] = if readall_formula.on_system_blocks_exist? ||
69+
cache[:valid_formulae][file] = if readall_formula.uses_on_system.present? ||
7070
formula_contents.match?(MACOS_MODULE_REGEX)
7171
[bottle_tag, *cache[:valid_formulae][file]]
7272
else

Library/Homebrew/sorbet/rbi/dsl/cask/cask.rbi

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)