Skip to content

Commit f0b7523

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 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 96d3277 commit f0b7523

File tree

9 files changed

+84
-38
lines changed

9 files changed

+84
-38
lines changed

Library/Homebrew/cask/audit.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ def audit_min_os
715715
cask_min_os = [on_system_block_min_os, cask.depends_on.macos&.minimum_version].compact.max
716716
odebug "Declared minimum OS version: #{cask_min_os&.to_sym}"
717717
return if cask_min_os&.to_sym == min_os.to_sym
718-
return if cask.on_system_blocks_exist? &&
718+
return if cask.uses_on_system.present? &&
719719
OnSystem.arch_condition_met?(:arm) &&
720720
cask_min_os.present? &&
721721
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
@@ -409,7 +409,7 @@ def to_hash_with_variations
409409
hash = to_h
410410
variations = {}
411411

412-
if @dsl.on_system_blocks_exist?
412+
if @dsl.uses_on_system.present?
413413
begin
414414
OnSystem::ALL_OS_ARCH_COMBINATIONS.each do |os, arch|
415415
bottle_tag = ::Utils::Bottles::Tag.new(system: os, arch:)

Library/Homebrew/cask/dsl.rb

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,27 +100,33 @@ class DSL
100100
:livecheck,
101101
:livecheck_defined?,
102102
:livecheckable?, # TODO: remove once `#livecheckable?` is removed
103-
:on_system_blocks_exist?,
104-
:on_system_block_min_os,
105103
:depends_on_set_in_block?,
104+
:on_system_block_min_os,
105+
:uses_on_system,
106106
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
107107
*ACTIVATABLE_ARTIFACT_CLASSES.map(&:dsl_key),
108108
*ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
109109
]).freeze
110110

111111
include OnSystem::MacOSAndLinux
112112

113-
attr_reader :cask, :token, :deprecation_date, :deprecation_reason, :deprecation_replacement, :disable_date,
114-
:disable_reason, :disable_replacement, :on_system_block_min_os
113+
attr_reader :cask, :token, :deprecation_date, :deprecation_reason,
114+
:deprecation_replacement, :disable_date, :disable_reason,
115+
:disable_replacement, :on_system_block_min_os
116+
117+
# A `UsesOnSystem` object that contains boolean instance variables
118+
# indicating whether the cask uses specific on_system methods.
119+
sig { returns(OnSystem::UsesOnSystem) }
120+
attr_reader :uses_on_system
115121

116122
def initialize(cask)
117123
@cask = cask
118124
@depends_on_set_in_block = T.let(false, T::Boolean)
119125
@deprecated = T.let(false, T::Boolean)
120126
@disabled = T.let(false, T::Boolean)
121127
@livecheck_defined = T.let(false, T::Boolean)
122-
@on_system_blocks_exist = T.let(false, T::Boolean)
123128
@token = cask.token
129+
@uses_on_system = T.let(OnSystem::UsesOnSystem.new, OnSystem::UsesOnSystem)
124130
end
125131

126132
sig { returns(T::Boolean) }
@@ -135,9 +141,6 @@ def disabled? = @disabled
135141
sig { returns(T::Boolean) }
136142
def livecheck_defined? = @livecheck_defined
137143

138-
sig { returns(T::Boolean) }
139-
def on_system_blocks_exist? = @on_system_blocks_exist
140-
141144
# Specifies the cask's name.
142145
#
143146
# NOTE: Multiple names can be specified.
@@ -353,8 +356,15 @@ def sha256(arg = nil, arm: nil, intel: nil, x86_64: nil, x86_64_linux: nil, arm6
353356

354357
x86_64 ||= intel if intel.present? && x86_64.nil?
355358
set_unique_stanza(:sha256, should_return) do
356-
if arm.present? || x86_64.present? || x86_64_linux.present? || arm64_linux.present?
357-
@on_system_blocks_exist = true
359+
@uses_on_system.arm = true if arm.present?
360+
@uses_on_system.intel = true if x86_64.present?
361+
if x86_64_linux.present?
362+
@uses_on_system.intel = true
363+
@uses_on_system.linux = true
364+
end
365+
if arm64_linux.present?
366+
@uses_on_system.arm = true
367+
@uses_on_system.linux = true
358368
end
359369

360370
val = arg || on_system_conditional(
@@ -385,7 +395,8 @@ def arch(arm: nil, intel: nil)
385395
should_return = arm.nil? && intel.nil?
386396

387397
set_unique_stanza(:arch, should_return) do
388-
@on_system_blocks_exist = true
398+
@uses_on_system.arm = true if arm
399+
@uses_on_system.intel = true if intel
389400

390401
on_arch_conditional(arm:, intel:)
391402
end
@@ -410,7 +421,8 @@ def os(macos: nil, linux: nil)
410421
should_return = macos.nil? && linux.nil?
411422

412423
set_unique_stanza(:os, should_return) do
413-
@on_system_blocks_exist = true
424+
@uses_on_system.macos = true if macos
425+
@uses_on_system.linux = true if linux
414426

415427
on_system_conditional(macos:, linux:)
416428
end

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ def generate_system_options(cask)
194194
# to on_system blocks referencing macOS versions.
195195
os_values = []
196196
arch_values = depends_on_archs.presence || []
197-
if cask.on_system_blocks_exist?
197+
if cask.uses_on_system.present?
198198
OnSystem::BASE_OS_OPTIONS.each do |os|
199199
os_values << if os == :macos
200200
(current_os_is_macos ? current_os : newest_macos)
@@ -230,7 +230,7 @@ def replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs)
230230
old_cask = begin
231231
Cask::CaskLoader.load(cask.sourcefile_path)
232232
rescue Cask::CaskInvalidError, Cask::CaskUnreadableError
233-
raise unless cask.on_system_blocks_exist?
233+
raise unless cask.uses_on_system.present?
234234
end
235235
next if old_cask.nil?
236236

@@ -257,7 +257,7 @@ def replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs)
257257
replacement_pairs << [/"#{old_hash}"/, ":no_check"] if old_hash != :no_check
258258
elsif old_hash == :no_check && new_hash != :no_check
259259
replacement_pairs << [":no_check", "\"#{new_hash}\""] if new_hash.is_a?(String)
260-
elsif new_hash && !cask.on_system_blocks_exist? && cask.languages.empty?
260+
elsif new_hash && cask.uses_on_system.blank? && cask.languages.empty?
261261
replacement_pairs << [old_hash.to_s, new_hash.to_s]
262262
elsif old_hash != :no_check
263263
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
@@ -303,7 +303,7 @@ def retrieve_pull_requests(formula_or_cask, name, version: nil)
303303
).returns(VersionBumpInfo)
304304
}
305305
def retrieve_versions_by_arch(formula_or_cask:, repositories:, name:)
306-
is_cask_with_blocks = formula_or_cask.is_a?(Cask::Cask) && formula_or_cask.on_system_blocks_exist?
306+
is_cask_with_blocks = formula_or_cask.is_a?(Cask::Cask) && formula_or_cask.uses_on_system.present?
307307
type, version_name = if formula_or_cask.is_a?(Formula)
308308
[:formula, "formula version:"]
309309
else

Library/Homebrew/extend/on_system.rb

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,28 @@ module OnSystem
99
ALL_OS_OPTIONS = [*MacOSVersion::SYMBOLS.keys, :linux].freeze
1010
ALL_OS_ARCH_COMBINATIONS = ALL_OS_OPTIONS.product(ARCH_OPTIONS).freeze
1111

12+
class UsesOnSystem < T::Struct
13+
prop :arm, T::Boolean, default: false
14+
prop :intel, T::Boolean, default: false
15+
prop :linux, T::Boolean, default: false
16+
prop :macos, T::Boolean, default: false
17+
18+
alias arm? arm
19+
alias intel? intel
20+
alias linux? linux
21+
alias macos? macos
22+
23+
# Whether the object has only default values.
24+
sig { returns(T::Boolean) }
25+
def empty?
26+
!@arm && !@intel && !@linux && !@macos
27+
end
28+
29+
# Whether the object has any non-default values.
30+
sig { returns(T::Boolean) }
31+
def present? = !empty?
32+
end
33+
1234
sig { params(arch: Symbol).returns(T::Boolean) }
1335
def self.arch_condition_met?(arch)
1436
raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch)
@@ -52,7 +74,8 @@ def self.condition_from_method_name(method_name)
5274
def self.setup_arch_methods(base)
5375
ARCH_OPTIONS.each do |arch|
5476
base.define_method(:"on_#{arch}") do |&block|
55-
@on_system_blocks_exist = true
77+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
78+
@uses_on_system.send(:"#{arch}=", true)
5679

5780
return unless OnSystem.arch_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
5881

@@ -65,7 +88,9 @@ def self.setup_arch_methods(base)
6588
end
6689

6790
base.define_method(:on_arch_conditional) do |arm: nil, intel: nil|
68-
@on_system_blocks_exist = true
91+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
92+
@uses_on_system.arm = true if arm
93+
@uses_on_system.intel = true if intel
6994

7095
if OnSystem.arch_condition_met? :arm
7196
arm
@@ -79,7 +104,8 @@ def self.setup_arch_methods(base)
79104
def self.setup_base_os_methods(base)
80105
BASE_OS_OPTIONS.each do |base_os|
81106
base.define_method(:"on_#{base_os}") do |&block|
82-
@on_system_blocks_exist = true
107+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
108+
@uses_on_system.send(:"#{base_os}=", true)
83109

84110
return unless OnSystem.os_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
85111

@@ -92,7 +118,9 @@ def self.setup_base_os_methods(base)
92118
end
93119

94120
base.define_method(:on_system) do |linux, macos:, &block|
95-
@on_system_blocks_exist = true
121+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
122+
@uses_on_system.linux = true
123+
@uses_on_system.macos = true if macos
96124

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

@@ -111,7 +139,9 @@ def self.setup_base_os_methods(base)
111139
end
112140

113141
base.define_method(:on_system_conditional) do |macos: nil, linux: nil|
114-
@on_system_blocks_exist = true
142+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
143+
@uses_on_system.macos = true if macos
144+
@uses_on_system.linux = true if linux
115145

116146
if OnSystem.os_condition_met?(:macos) && macos.present?
117147
macos
@@ -125,7 +155,8 @@ def self.setup_base_os_methods(base)
125155
def self.setup_macos_methods(base)
126156
MacOSVersion::SYMBOLS.each_key do |os_name|
127157
base.define_method(:"on_#{os_name}") do |or_condition = nil, &block|
128-
@on_system_blocks_exist = true
158+
@uses_on_system ||= T.let(OnSystem::UsesOnSystem.new, T.nilable(OnSystem::UsesOnSystem))
159+
@uses_on_system.macos = true
129160

130161
os_condition = OnSystem.condition_from_method_name T.must(__method__)
131162
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
@@ -265,7 +265,7 @@ def initialize(name, path, spec, alias_path: nil, tap: nil, force_bottle: false)
265265
@follow_installed_alias = T.let(true, T::Boolean)
266266
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
267267
@oldname_locks = T.let([], T::Array[FormulaLock])
268-
@on_system_blocks_exist = T.let(false, T::Boolean)
268+
@uses_on_system = T.let(OnSystem::UsesOnSystem.new, OnSystem::UsesOnSystem)
269269
end
270270

271271
sig { params(spec_sym: Symbol).void }
@@ -2588,7 +2588,7 @@ def to_hash_with_variations
25882588

25892589
variations = {}
25902590

2591-
if path.exist? && on_system_blocks_exist?
2591+
if path.exist? && uses_on_system.present?
25922592
formula_contents = path.read
25932593
OnSystem::ALL_OS_ARCH_COMBINATIONS.each do |os, arch|
25942594
bottle_tag = Utils::Bottles::Tag.new(system: os, arch:)
@@ -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)