Merge pull request #23433 from Homebrew/cask-explicit-os-support

Treat cask OS support as explicit data
This commit is contained in:
Mike McQuaid
2026-08-05 16:24:09 +00:00
committed by GitHub
7 changed files with 73 additions and 19 deletions
-2
View File
@@ -616,8 +616,6 @@ module Cask
if dsl!.on_system_blocks_exist?
begin
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
next if bottle_tag.linux? && dsl!.os.nil? && !dsl!.sha256_set_for_linux? && !dsl!.on_linux_blocks_exist?
macos_requirements = [depends_on.macos, depends_on.maximum_macos].compact
next if bottle_tag.macos? &&
macos_requirements.present? &&
-10
View File
@@ -128,7 +128,6 @@ module Cask
:no_autobump_message,
:on_system_blocks_exist?,
:on_os_blocks_exist?,
:on_linux_blocks_exist?,
:on_system_block_min_os,
:depends_on_set_in_block?,
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
@@ -233,13 +232,11 @@ module Cask
@no_autobump_message = T.let(nil, T.nilable(T.any(String, Symbol)))
@on_system_blocks_exist = T.let(false, T::Boolean)
@on_os_blocks_exist = T.let(false, T::Boolean)
@on_linux_blocks_exist = T.let(false, T::Boolean)
@on_system_block_min_os = T.let(nil, T.nilable(MacOSVersion))
@os = T.let(nil, T.nilable(String))
@os_set_in_block = T.let(false, T::Boolean)
@rename = T.let([], T::Array[DSL::Rename])
@sha256 = T.let(nil, T.nilable(T.any(Checksum, Symbol)))
@sha256_set_for_linux = T.let(false, T::Boolean)
@sha256_set_in_block = T.let(false, T::Boolean)
@staged_path = T.let(nil, T.nilable(Pathname))
@token = T.let(cask.token, String)
@@ -267,12 +264,6 @@ module Cask
sig { returns(T::Boolean) }
def on_os_blocks_exist? = @on_os_blocks_exist
sig { returns(T::Boolean) }
def on_linux_blocks_exist? = @on_linux_blocks_exist
sig { returns(T::Boolean) }
def sha256_set_for_linux? = @sha256_set_for_linux
# Specifies the cask's name.
#
# NOTE: Multiple names can be specified.
@@ -560,7 +551,6 @@ module Cask
if arm.present? || x86_64.present? || x86_64_linux.present? || arm64_linux.present?
@on_system_blocks_exist = true
end
@sha256_set_for_linux = true if x86_64_linux.present? || arm64_linux.present?
val = arg || on_system_conditional(
macos: on_arch_conditional(arm:, intel: x86_64),
+15
View File
@@ -358,6 +358,7 @@ on_request: true)
sig { void }
def check_requirements
check_stanza_os_requirements
check_supported_system
check_macos_requirements
check_arch_requirements
end
@@ -369,6 +370,20 @@ on_request: true)
raise CaskError, "#{@cask}: This cask requires Linux."
end
sig { void }
def check_supported_system
# Audited casks always have an activatable artifact for the systems they
# support, so API data without one means this system is unsupported.
# Source loads keep working for unaudited casks, e.g. naked containers.
return unless @cask.loaded_from_api?
return if @cask.artifacts.any? do |artifact|
artifact.respond_to?(:install_phase) || artifact.is_a?(Artifact::StageOnly)
end
os_name = Homebrew::SimulateSystem.simulating_or_running_on_macos? ? "macOS" : "Linux"
raise CaskError, "#{@cask}: This cask is not available on #{os_name}."
end
sig { void }
def check_macos_requirements
macos_requirement = [@cask.depends_on.macos, @cask.depends_on.maximum_macos].compact.find { !it.satisfied? }
-2
View File
@@ -88,7 +88,6 @@ module OnSystem
base.define_method(:"on_#{base_os}") do |&block|
@on_system_blocks_exist = T.let(true, T.nilable(TrueClass))
@on_os_blocks_exist = T.let(true, T.nilable(TrueClass))
@on_linux_blocks_exist = T.let(true, T.nilable(TrueClass)) if base_os == :linux
return unless OnSystem.os_condition_met? OnSystem.condition_from_method_name(T.must(__method__))
@@ -105,7 +104,6 @@ module OnSystem
base.define_method(:on_system) do |linux, macos:, &block|
@on_system_blocks_exist = T.let(true, T.nilable(TrueClass))
@on_os_blocks_exist = T.let(true, T.nilable(TrueClass))
@on_linux_blocks_exist = T.let(true, T.nilable(TrueClass))
raise ArgumentError, "The first argument to `on_system` must be `:linux`" if linux != :linux
-3
View File
@@ -159,9 +159,6 @@ class Cask::Cask
sig { params(args: T.untyped, block: T.untyped).returns(T.untyped) }
def no_autobump_message(*args, &block); end
sig { params(args: T.untyped, block: T.untyped).returns(T::Boolean) }
def on_linux_blocks_exist?(*args, &block); end
sig { params(args: T.untyped, block: T.untyped).returns(T::Boolean) }
def on_os_blocks_exist?(*args, &block); end
+17
View File
@@ -757,6 +757,16 @@ RSpec.describe Cask::Cask, :cask do
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.0.0/intel.zip",
"version": "1.0.0",
"sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216"
},
"x86_64_linux": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin//intel.zip",
"version": null,
"sha256": null
},
"arm64_linux": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin-arm64//arm.zip",
"version": null,
"sha256": null
}
}
JSON
@@ -795,6 +805,13 @@ RSpec.describe Cask::Cask, :cask do
"catalina": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine-intel.zip",
"sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
},
"x86_64_linux": {
"url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine-intel.zip",
"sha256": null
},
"arm64_linux": {
"sha256": null
}
}
JSON
+41 -2
View File
@@ -231,6 +231,41 @@ RSpec.describe Cask::Installer, :cask do
end.to raise_error(Cask::CaskError, /\Awith-depends-on-arch: This cask depends on hardware architecture/)
end
it "names the cask when it has nothing to install on this system" do
no_artifacts_cask = Cask::Cask.new("with-no-artifacts", loaded_from_api: true) do
version "1.0"
sha256 :no_check
url "https://brew.sh/x.zip"
end
expect do
described_class.new(no_artifacts_cask).check_supported_system
end.to raise_error(Cask::CaskError, "with-no-artifacts: This cask is not available on macOS.")
end
it "treats uninstall-only artifacts as nothing to install" do
zap_only_cask = Cask::Cask.new("with-zap-only", loaded_from_api: true) do
version "1.0"
sha256 :no_check
url "https://brew.sh/x.zip"
zap trash: "~/Library/Caches/brew-test"
end
expect do
described_class.new(zap_only_cask).check_supported_system
end.to raise_error(Cask::CaskError, "with-zap-only: This cask is not available on macOS.")
end
it "does not treat stage_only casks as having nothing to install" do
stage_only_cask = Cask::Cask.new("with-stage-only", loaded_from_api: true) do
version "1.0"
sha256 :no_check
url "https://brew.sh/x.zip"
stage_only true
end
expect do
described_class.new(stage_only_cask).check_supported_system
end.not_to raise_error
end
it "installs fine if sha256 :no_check is used with --require-sha and --force" do
no_checksum = Cask::CaskLoader.load(cask_path("no-checksum"))
@@ -385,7 +420,7 @@ RSpec.describe Cask::Installer, :cask do
expect(Homebrew::API::Cask).to receive(:source_download_cask).once.and_return(source_caffeine)
caffeine = Cask::CaskLoader.load(path)
expect(caffeine).to receive(:loaded_from_api?).once.and_return(true)
allow(caffeine).to receive(:loaded_from_api?).and_return(true)
expect(caffeine).to receive(:caskfile_only?).once.and_return(true)
described_class.new(caffeine).install
@@ -511,7 +546,7 @@ RSpec.describe Cask::Installer, :cask do
expect(Homebrew::API::Cask).to receive(:source_download_cask).twice.and_return(source_caffeine)
caffeine = Cask::CaskLoader.load(path)
expect(caffeine).to receive(:loaded_from_api?).twice.and_return(true)
allow(caffeine).to receive(:loaded_from_api?).and_return(true)
expect(caffeine).to receive(:caskfile_only?).twice.and_return(true)
expect(caffeine).to receive(:installed_caskfile).once.and_return(invalid_path)
@@ -693,6 +728,7 @@ RSpec.describe Cask::Installer, :cask do
ENV["HOMEBREW_FORBIDDEN_CASKS"] = cask_name = "homebrew-forbidden-cask"
cask = Cask::Cask.new(cask_name) do
url "file://#{TEST_FIXTURE_DIR}/cask/container.tar.gz"
app "Fake.app"
end
allow(cask).to receive_messages(loaded_from_api?: true, caskfile_only?: true)
installer = described_class.new(cask)
@@ -710,6 +746,7 @@ RSpec.describe Cask::Installer, :cask do
url "https://example.com/source-cask.zip"
version "0.9"
sha256 "d7b9f4e8bf83608b71fe958a99f19f2e5e68bb2582965d32e41759c24f1aef97"
app "Fake.app"
end
cask_struct = Homebrew::API::CaskStruct.new(
sha256: "d7b9f4e8bf83608b71fe958a99f19f2e5e68bb2582965d32e41759c24f1aef97",
@@ -755,6 +792,7 @@ RSpec.describe Cask::Installer, :cask do
it "enqueues source API caskfiles before the main cask download" do
cask = Cask::Cask.new("source-api-cask") do
url "file://#{TEST_FIXTURE_DIR}/cask/container.tar.gz"
app "Fake.app"
end
allow(cask).to receive_messages(loaded_from_api?: true, caskfile_only?: true, languages: ["en"])
download_queue = instance_double(Homebrew::DownloadQueue)
@@ -772,6 +810,7 @@ RSpec.describe Cask::Installer, :cask do
it "leaves source API caskfiles in the main queue when their URL is known" do
cask = Cask::Cask.new("source-api-cask") do
url "file://#{TEST_FIXTURE_DIR}/cask/container.tar.gz"
app "Fake.app"
end
allow(cask).to receive_messages(loaded_from_api?: true, caskfile_only?: true, languages: [])
download_queue = instance_double(Homebrew::DownloadQueue)