Skip to content

Commit 4a9216b

Browse files
committed
Filter Linux cask loads by support
- Keep `brew audit --tap` and `brew readall` loading Linux-supported casks so Linux syntax errors still surface. - Skip macOS-only casks before Linux reloads because their macOS `sha256 arm:/intel:` shorthand is invalid in a Linux context. - Fixes #22148.
1 parent 0f9224a commit 4a9216b

5 files changed

Lines changed: 145 additions & 8 deletions

File tree

Library/Homebrew/dev-cmd/audit.rb

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ def run
132132

133133
if tap.formula_file?(file)
134134
audit_formulae << Formulary.factory(absolute_file)
135-
elsif tap.cask_file?(file)
136-
audit_casks << Cask::CaskLoader.load(absolute_file)
135+
elsif tap.cask_file?(file) && (cask = cask_for_audit(absolute_file, os_arch_combinations))
136+
audit_casks << cask
137137
end
138138
end
139139

@@ -142,7 +142,7 @@ def run
142142
Tap.fetch(args.tap).then do |tap|
143143
[
144144
tap.formula_files.map { |path| Formulary.factory(path) },
145-
tap.cask_files.map { |path| Cask::CaskLoader.load(path) },
145+
tap.cask_files.filter_map { |path| cask_for_audit(path, os_arch_combinations) },
146146
]
147147
end
148148
elsif args.installed?
@@ -342,6 +342,26 @@ def run
342342

343343
private
344344

345+
sig {
346+
params(
347+
path: T.any(String, Pathname),
348+
os_arch_combinations: T::Array[[Symbol, Symbol]],
349+
).returns(T.nilable(Cask::Cask))
350+
}
351+
def cask_for_audit(path, os_arch_combinations)
352+
cask_audit_os, cask_audit_arch =
353+
os_arch_combinations.find { |os, _arch| os != :linux } || os_arch_combinations.fetch(0)
354+
355+
if cask_audit_os == :linux
356+
supports_linux = SimulateSystem.with(os: :macos, arch: cask_audit_arch) do
357+
Cask::CaskLoader.load(path).supports_linux?
358+
end
359+
return unless supports_linux
360+
end
361+
362+
SimulateSystem.with(os: cask_audit_os, arch: cask_audit_arch) { Cask::CaskLoader.load(path) }
363+
end
364+
345365
sig { params(results: T::Hash[[Symbol, Pathname], T::Array[T::Hash[Symbol, T.untyped]]]).void }
346366
def print_problems(results)
347367
results.each do |(name, path), problems|

Library/Homebrew/extend/os/mac/readall.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module ClassMethods
1414

1515
sig { params(tap: ::Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
1616
def valid_casks?(tap, os_name: nil, arch: ::Hardware::CPU.type)
17-
return true if os_name == :linux
17+
return super if os_name == :linux
1818

1919
current_macos_version = if os_name.is_a?(Symbol)
2020
MacOSVersion.from_symbol(os_name)

Library/Homebrew/readall.rb

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,34 @@ def self.valid_formulae?(tap, bottle_tag: nil)
9090
success
9191
end
9292

93-
sig { params(_tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
94-
def self.valid_casks?(_tap, os_name: nil, arch: nil)
95-
true
93+
sig { params(tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
94+
def self.valid_casks?(tap, os_name: nil, arch: nil)
95+
return true if os_name != :linux && !(os_name.nil? && Homebrew::SimulateSystem.current_os == :linux)
96+
97+
success = T.let(true, T::Boolean)
98+
tap.cask_files.each do |file|
99+
if arch
100+
next unless Homebrew::SimulateSystem.with(os: :macos, arch:) do
101+
Cask::CaskLoader.load(file).supports_linux?
102+
end
103+
104+
Homebrew::SimulateSystem.with(os: :linux, arch:) { Cask::CaskLoader.load(file) }
105+
else
106+
next unless Homebrew::SimulateSystem.with(os: :macos) { Cask::CaskLoader.load(file).supports_linux? }
107+
108+
Homebrew::SimulateSystem.with(os: :linux) { Cask::CaskLoader.load(file) }
109+
end
110+
rescue Interrupt
111+
raise
112+
# Handle all possible exceptions reading casks.
113+
rescue Exception => e # rubocop:disable Lint/RescueException
114+
os_and_arch = "Linux"
115+
os_and_arch += " on #{arch}" if arch
116+
onoe "Invalid cask (#{os_and_arch}): #{file}"
117+
$stderr.puts e
118+
success = false
119+
end
120+
success
96121
end
97122

98123
sig {

Library/Homebrew/test/cmd/readall_spec.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,48 @@
2020
.and not_to_output.to_stdout
2121
.and not_to_output.to_stderr
2222
end
23+
24+
it "skips macOS-only casks when loading tap casks on Linux" do
25+
tap_path = mktmpdir
26+
macos_only_cask_file = tap_path/"Casks/macos-only-example.rb"
27+
linux_cask_file = tap_path/"Casks/linux-example.rb"
28+
macos_only_cask_file.dirname.mkpath
29+
macos_only_cask_file.write <<~RUBY
30+
cask "macos-only-example" do
31+
version "1.0"
32+
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
33+
intel: "1111111111111111111111111111111111111111111111111111111111111111"
34+
url "https://example.invalid/x.pkg"
35+
name "Example"
36+
desc "macOS-only cask"
37+
homepage "https://example.invalid/"
38+
depends_on macos: ">= :ventura"
39+
pkg "x.pkg"
40+
end
41+
RUBY
42+
linux_cask_file.write <<~RUBY
43+
cask "linux-example" do
44+
version "1.0"
45+
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
46+
intel: "1111111111111111111111111111111111111111111111111111111111111111"
47+
url "https://example.invalid/x.tar.gz"
48+
name "Example"
49+
desc "Linux-supported cask"
50+
homepage "https://example.invalid/"
51+
binary "x"
52+
end
53+
RUBY
54+
55+
success = nil
56+
expect do
57+
success = Homebrew::SimulateSystem.with(os: :linux) do
58+
Readall.valid_tap?(
59+
instance_double(Tap, formula_files: [], cask_files: [macos_only_cask_file, linux_cask_file]),
60+
os_arch_combinations: [[:linux, :arm]],
61+
)
62+
end
63+
end.to output(a_string_matching(/\A(?=.*linux-example)(?!.*macos-only-example).*\z/m)).to_stderr
64+
65+
expect(success).to be false
66+
end
2367
end
Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,57 @@
1-
# typed: strict
1+
# typed: false
22
# frozen_string_literal: true
33

44
require "dev-cmd/audit"
55
require "cmd/shared_examples/args_parse"
66

77
RSpec.describe Homebrew::DevCmd::Audit do
88
it_behaves_like "parseable arguments"
9+
10+
describe "#run" do
11+
subject(:audit) { described_class.new(["--tap=homebrew/test"]) }
12+
13+
let(:tap_path) { mktmpdir }
14+
let(:macos_only_cask_file) { tap_path/"Casks/macos-only-example.rb" }
15+
let(:linux_cask_file) { tap_path/"Casks/linux-example.rb" }
16+
let(:tap) { instance_double(Tap, formula_files: [], cask_files: [macos_only_cask_file, linux_cask_file]) }
17+
18+
before do
19+
macos_only_cask_file.dirname.mkpath
20+
macos_only_cask_file.write <<~RUBY
21+
cask "macos-only-example" do
22+
version "1.0"
23+
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
24+
intel: "1111111111111111111111111111111111111111111111111111111111111111"
25+
url "https://example.invalid/x.pkg"
26+
name "Example"
27+
desc "macOS-only cask"
28+
homepage "https://example.invalid/"
29+
depends_on macos: ">= :ventura"
30+
pkg "x.pkg"
31+
end
32+
RUBY
33+
linux_cask_file.write <<~RUBY
34+
cask "linux-example" do
35+
version "1.0"
36+
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
37+
intel: "1111111111111111111111111111111111111111111111111111111111111111"
38+
url "https://example.invalid/x.tar.gz"
39+
name "Example"
40+
desc "Linux-supported cask"
41+
homepage "https://example.invalid/"
42+
binary "x"
43+
end
44+
RUBY
45+
46+
allow(Homebrew).to receive(:install_bundler_gems!)
47+
allow(Tap).to receive(:fetch).with("homebrew/test").and_return(tap)
48+
allow(Tap).to receive(:installed).and_return([])
49+
end
50+
51+
it "skips macOS-only casks when loading tap casks on Linux" do
52+
Homebrew::SimulateSystem.with(os: :linux) do
53+
expect { audit.run }.to raise_error(Cask::CaskInvalidError, /linux-example.*invalid 'sha256'/)
54+
end
55+
end
56+
end
957
end

0 commit comments

Comments
 (0)