Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions Library/Homebrew/dev-cmd/audit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ def run
Formulary.enable_factory_cache!

os_arch_combinations = args.os_arch_combinations
cask_audit_os, cask_audit_arch =
os_arch_combinations.find { |os, _arch| os != :linux } || os_arch_combinations.fetch(0)

Homebrew.auditing = true
Homebrew.inject_dump_stats!(FormulaAuditor, /^audit_/) if args.audit_debug?
Expand Down Expand Up @@ -132,8 +134,8 @@ def run

if tap.formula_file?(file)
audit_formulae << Formulary.factory(absolute_file)
elsif tap.cask_file?(file)
audit_casks << Cask::CaskLoader.load(absolute_file)
elsif tap.cask_file?(file) && (cask = cask_for_audit(absolute_file, cask_audit_os, cask_audit_arch))
audit_casks << cask
end
end

Expand All @@ -142,7 +144,7 @@ def run
Tap.fetch(args.tap).then do |tap|
[
tap.formula_files.map { |path| Formulary.factory(path) },
tap.cask_files.map { |path| Cask::CaskLoader.load(path) },
tap.cask_files.filter_map { |path| cask_for_audit(path, cask_audit_os, cask_audit_arch) },
]
end
elsif args.installed?
Expand Down Expand Up @@ -342,6 +344,30 @@ def run

private

sig {
params(
path: T.any(String, Pathname),
cask_audit_os: Symbol,
cask_audit_arch: Symbol,
).returns(T.nilable(Cask::Cask))
}
def cask_for_audit(path, cask_audit_os, cask_audit_arch)
if cask_audit_os == :linux
return if Pathname(path).read.match?(/^\s*depends_on(?:\s*\(\s*|\s+)(?::macos\b|macos:)/)

cask = SimulateSystem.with(os: :macos, arch: cask_audit_arch) do
loaded_cask = Cask::CaskLoader.load(path)
loaded_cask if loaded_cask.supports_linux?
end
return unless cask

SimulateSystem.with(os: :linux, arch: cask_audit_arch) { cask.refresh }
return cask
end

SimulateSystem.with(os: cask_audit_os, arch: cask_audit_arch) { Cask::CaskLoader.load(path) }
end

sig { params(results: T::Hash[[Symbol, Pathname], T::Array[T::Hash[Symbol, T.untyped]]]).void }
def print_problems(results)
results.each do |(name, path), problems|
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/extend/os/mac/readall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module ClassMethods

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

current_macos_version = if os_name.is_a?(Symbol)
MacOSVersion.from_symbol(os_name)
Expand Down
45 changes: 42 additions & 3 deletions Library/Homebrew/readall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,48 @@ def self.valid_formulae?(tap, bottle_tag: nil)
success
end

sig { params(_tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
def self.valid_casks?(_tap, os_name: nil, arch: nil)
true
sig { params(tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
def self.valid_casks?(tap, os_name: nil, arch: nil)
validating_linux = if os_name.nil?
Homebrew::SimulateSystem.current_os == :linux
else
os_name == :linux
end
return true unless validating_linux

success = T.let(true, T::Boolean)
tap.cask_files.each do |file|
next if file.read.match?(/^\s*depends_on(?:\s*\(\s*|\s+)(?::macos\b|macos:)/)

cask = if arch
Homebrew::SimulateSystem.with(os: :macos, arch:) do
loaded_cask = Cask::CaskLoader.load(file)
loaded_cask if loaded_cask.supports_linux?
end
else
Homebrew::SimulateSystem.with(os: :macos) do
loaded_cask = Cask::CaskLoader.load(file)
loaded_cask if loaded_cask.supports_linux?
end
end
next unless cask

if arch
Homebrew::SimulateSystem.with(os: :linux, arch:) { cask.refresh }
else
Homebrew::SimulateSystem.with(os: :linux) { cask.refresh }
end
Comment thread
MikeMcQuaid marked this conversation as resolved.
rescue Interrupt
raise
# Handle all possible exceptions reading casks.
rescue Exception => e # rubocop:disable Lint/RescueException
os_and_arch = "Linux"
os_and_arch += " on #{arch}" if arch
onoe "Invalid cask (#{os_and_arch}): #{file}"
$stderr.puts e
success = false
end
success
end

sig {
Expand Down
44 changes: 44 additions & 0 deletions Library/Homebrew/test/cmd/readall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,48 @@
.and not_to_output.to_stdout
.and not_to_output.to_stderr
end

it "skips macOS-only casks when loading tap casks on Linux" do
tap_path = mktmpdir
macos_only_cask_file = tap_path/"Casks/macos-only-example.rb"
linux_cask_file = tap_path/"Casks/linux-example.rb"
macos_only_cask_file.dirname.mkpath
macos_only_cask_file.write <<~RUBY
cask "macos-only-example" do
version "1.0"
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
intel: "1111111111111111111111111111111111111111111111111111111111111111"
url "https://example.invalid/x.pkg"
name "Example"
desc "macOS-only cask"
homepage "https://example.invalid/"
depends_on macos: ">= :ventura"
binary "x"
end
RUBY
linux_cask_file.write <<~RUBY
cask "linux-example" do
version "1.0"
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
intel: "1111111111111111111111111111111111111111111111111111111111111111"
url "https://example.invalid/x.tar.gz"
name "Example"
desc "Linux-supported cask"
homepage "https://example.invalid/"
binary "x"
end
RUBY

success = nil
expect do
success = Homebrew::SimulateSystem.with(os: :linux) do
Readall.valid_tap?(
instance_double(Tap, formula_files: [], cask_files: [macos_only_cask_file, linux_cask_file]),
os_arch_combinations: [[:linux, :arm]],
)
end
end.to output(a_string_matching(/\A(?=.*linux-example)(?!.*macos-only-example).*\z/m)).to_stderr

expect(success).to be false
end
end
51 changes: 50 additions & 1 deletion Library/Homebrew/test/dev-cmd/audit_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,58 @@
# typed: strict
# typed: false
# frozen_string_literal: true

require "dev-cmd/audit"
require "cmd/shared_examples/args_parse"

RSpec.describe Homebrew::DevCmd::Audit do
it_behaves_like "parseable arguments"

describe "#run" do
subject(:audit) { described_class.new(["--tap=homebrew/test"]) }

let(:tap_path) { mktmpdir }
let(:macos_only_cask_file) { tap_path/"Casks/macos-only-example.rb" }
let(:linux_cask_file) { tap_path/"Casks/linux-example.rb" }
let(:tap) { instance_double(Tap, formula_files: [], cask_files: [macos_only_cask_file, linux_cask_file]) }

before do
macos_only_cask_file.dirname.mkpath
macos_only_cask_file.write <<~RUBY
cask "macos-only-example" do
version "1.0"
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
intel: "1111111111111111111111111111111111111111111111111111111111111111"
url "https://example.invalid/x.pkg"
name "Example"
desc "macOS-only cask"
homepage "https://example.invalid/"
depends_on macos: ">= :ventura"
binary "x"
end
RUBY
linux_cask_file.write <<~RUBY
cask "linux-example" do
version "1.0"
sha256 arm: "0000000000000000000000000000000000000000000000000000000000000000",
intel: "1111111111111111111111111111111111111111111111111111111111111111"
url "https://example.invalid/x.tar.gz"
name "Example"
desc "Linux-supported cask"
homepage "https://example.invalid/"
binary "x"
end
RUBY

allow(Homebrew).to receive(:install_bundler_gems!)
allow(Tap).to receive(:fetch).and_call_original
allow(Tap).to receive(:fetch).with("homebrew/test").and_return(tap)
allow(Tap).to receive(:installed).and_return([])
end

it "skips macOS-only casks when loading tap casks on Linux" do
Homebrew::SimulateSystem.with(os: :linux) do
expect { audit.run }.to raise_error(Cask::CaskInvalidError, /linux-example.*invalid 'sha256'/)
end
end
end
end
Loading