Skip to content

Commit 2559e6d

Browse files
committed
resource_auditor: avoid hardcoding PyPI formulae
Signed-off-by: botantony <antonsm21@gmail.com>
1 parent bbd8811 commit 2559e6d

File tree

4 files changed

+52
-29
lines changed

4 files changed

+52
-29
lines changed

Library/Homebrew/formula_auditor.rb

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -731,10 +731,11 @@ def get_repo_data(regex)
731731
def audit_specs
732732
problem "HEAD-only (no stable download)" if head_only?(formula) && @core_tap
733733

734-
allowed_pypi_packages = formula.tap&.audit_exception(:pypi_resources_allowlist, formula.name)
735-
allowed_pypi_packages = case allowed_pypi_packages
736-
when String
737-
allowed_pypi_packages.split(/\s+/i).to_set
734+
allowed_pypi_packages = if (resources_allowlist = formula
735+
.tap
736+
&.audit_exception(:pypi_resources_allowlist, formula.name)
737+
.presence)
738+
Set.new(resources_allowlist.split(/\s+/i))
738739
else
739740
Set.new
740741
end
@@ -761,15 +762,13 @@ def audit_specs
761762
spec.resources.each_value do |resource|
762763
problem "Resource name should be different from the formula name" if resource.name == formula.name
763764

764-
except = if allowed_pypi_packages.include?(resource.name)
765-
@except.to_a + ["pypi_resources"]
766-
else
767-
@except
768-
end
765+
except = @except
766+
except = [*Array(except), "pypi_resources"] if allowed_pypi_packages.include?(resource.name)
769767

770768
ra = ResourceAuditor.new(
771769
resource, spec_name,
772770
online: @online, strict: @strict, only: @only, except:,
771+
pypi_formulae: formula.tap&.pypi_dependencies_formulae,
773772
use_homebrew_curl: resource.using == :homebrew_curl
774773
).audit
775774
ra.problems.each do |message|

Library/Homebrew/resource_auditor.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ module Homebrew
88
class ResourceAuditor
99
include Utils::Curl
1010

11-
DEPENDENCY_PACKAGES = Set.new(%w[certifi cffi cryptography numpy pillow pydantic rpds-py scipy torch]).freeze
12-
1311
attr_reader :name, :version, :checksum, :url, :mirrors, :using, :specs, :owner, :spec_name, :problems
1412

1513
def initialize(resource, spec_name, options = {})
@@ -27,6 +25,7 @@ def initialize(resource, spec_name, options = {})
2725
@only = options[:only]
2826
@except = options[:except]
2927
@core_tap = options[:core_tap]
28+
@pypi_formulae = options[:pypi_formulae] || []
3029
@use_homebrew_curl = options[:use_homebrew_curl]
3130
@problems = []
3231
end
@@ -130,9 +129,12 @@ def audit_pypi_resources
130129
problem "`resource` name should be '#{pypi_package_name}' to match the PyPI package name"
131130
end
132131

133-
return if DEPENDENCY_PACKAGES.exclude?(pypi_package_name.to_s.downcase)
132+
pypi_package_name = pypi_package_name.to_s.downcase
133+
134+
return if @pypi_formulae.exclude?(pypi_package_name)
134135

135-
problem "PyPI package should be replaced with Homebrew dependency and excluded using `pypi_package` method"
136+
problem "PyPI package should be replaced with `depends_on \"#{pypi_package_name}\"` " \
137+
"and excluded using `pypi_package` method"
136138
end
137139

138140
def audit_urls

Library/Homebrew/tap.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class Tap
2929
private_constant :HOMEBREW_TAP_SYNCED_VERSIONS_FORMULAE_FILE
3030
HOMEBREW_TAP_DISABLED_NEW_USR_LOCAL_RELOCATION_FORMULAE_FILE = "disabled_new_usr_local_relocation_formulae.json"
3131
private_constant :HOMEBREW_TAP_DISABLED_NEW_USR_LOCAL_RELOCATION_FORMULAE_FILE
32+
HOMEBREW_TAP_PYPI_DEPENDENCIES_FORMULAE = "pypi_dependencies_formulae.json"
33+
private_constant :HOMEBREW_TAP_PYPI_DEPENDENCIES_FORMULAE
3234
HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions"
3335
private_constant :HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR
3436
HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR = "style_exceptions"
@@ -40,6 +42,7 @@ class Tap
4042
#{HOMEBREW_TAP_MIGRATIONS_FILE}
4143
#{HOMEBREW_TAP_SYNCED_VERSIONS_FORMULAE_FILE}
4244
#{HOMEBREW_TAP_DISABLED_NEW_USR_LOCAL_RELOCATION_FORMULAE_FILE}
45+
#{HOMEBREW_TAP_PYPI_DEPENDENCIES_FORMULAE}
4346
#{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json
4447
#{HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR}/*.json
4548
].freeze, T::Array[String])
@@ -1102,6 +1105,19 @@ def disabled_new_usr_local_relocation_formulae
11021105
)
11031106
end
11041107

1108+
# Array with PyPI packages that should be used as dependencies
1109+
sig { overridable.returns(T::Array[String]) }
1110+
def pypi_dependencies_formulae
1111+
@pypi_dependencies_formulae ||= T.let(
1112+
if (synced_file = path/HOMEBREW_TAP_PYPI_DEPENDENCIES_FORMULAE).file?
1113+
JSON.parse(synced_file.read)
1114+
else
1115+
[]
1116+
end,
1117+
T.nilable(T::Array[String]),
1118+
)
1119+
end
1120+
11051121
sig { returns(T::Boolean) }
11061122
def should_report_analytics?
11071123
installed? && !private?

Library/Homebrew/test/formula_auditor_spec.rb

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ def formula_auditor(name, text, options = {})
2929

3030
if options.key? :tap_audit_exceptions
3131
tap = Tap.fetch("test/tap")
32-
allow(tap).to receive(:audit_exceptions).and_return(options[:tap_audit_exceptions])
32+
allow(tap).to receive_messages(
33+
audit_exceptions: options[:tap_audit_exceptions],
34+
pypi_dependencies_formulae: options[:pypi_dependencies_formulae] || [],
35+
)
3336
allow(formula).to receive(:tap).and_return(tap)
3437
options.delete :tap_audit_exceptions
3538
end
@@ -526,6 +529,8 @@ class Foo < Formula
526529
end
527530

528531
describe "#audit_pypi_resources" do
532+
let(:pypi_dependencies_formulae) { ["bar", "baz"] }
533+
529534
it "reports a problem if the resource name does not match the python sdist name" do
530535
fa = formula_auditor "foo", <<~RUBY
531536
class Foo < Formula
@@ -565,19 +570,19 @@ class Foo < Formula
565570
end
566571

567572
it "reports a problem if the resource should be replaced with a dependency" do
568-
fa = formula_auditor "foo", <<~RUBY
573+
fa = formula_auditor("foo", <<~RUBY, tap_audit_exceptions: {}, pypi_dependencies_formulae:)
569574
class Foo < Formula
570575
url "https://brew.sh/foo-1.0.tgz"
571576
sha256 "abc123"
572577
homepage "https://brew.sh"
573578
574-
resource "cryptography" do
575-
url "https://files.pythonhosted.org/packages/00/00/aaaa/cryptography-1.0.0.tar.gz"
579+
resource "bar" do
580+
url "https://files.pythonhosted.org/packages/00/00/aaaa/bar-1.0.0.tar.gz"
576581
sha256 "def456"
577582
end
578583
579-
resource "pydantic" do
580-
url "https://files.pythonhosted.org/packages/00/00/aaaa/pydantic-1.0.0.tar.gz"
584+
resource "baz" do
585+
url "https://files.pythonhosted.org/packages/00/00/aaaa/baz-1.0.0.tar.gz"
581586
sha256 "ghi789"
582587
end
583588
end
@@ -586,24 +591,25 @@ class Foo < Formula
586591
fa.audit_specs
587592
expect(fa.problems.count).to eq(2)
588593
expect(fa.problems.first[:message])
589-
.to match("PyPI package should be replaced with Homebrew dependency and excluded using `pypi_package` method")
594+
.to match("PyPI package should be replaced with `depends_on \"bar\"` " \
595+
"and excluded using `pypi_package` method")
590596
end
591597

592598
it "doesn't report a problem if there is an exception to a PyPI resource that should be a dependency" do
593-
tap_audit_exceptions = { pypi_resources_allowlist: { "foo" => "cryptography pydantic" } }
594-
fa = formula_auditor("foo", <<~RUBY, tap_audit_exceptions:)
599+
tap_audit_exceptions = { pypi_resources_allowlist: { "foo" => "bar baz" } }
600+
fa = formula_auditor("foo", <<~RUBY, tap_audit_exceptions:, pypi_dependencies_formulae:)
595601
class Foo < Formula
596602
url "https://brew.sh/foo-1.0.tgz"
597603
sha256 "abc123"
598604
homepage "https://brew.sh"
599605
600-
resource "cryptography" do
601-
url "https://files.pythonhosted.org/packages/60/04/aaaa/cryptography-1.0.0.tar.gz"
606+
resource "bar" do
607+
url "https://files.pythonhosted.org/packages/00/00/aaaa/bar-1.0.0.tar.gz"
602608
sha256 "def456"
603609
end
604610
605-
resource "pydantic" do
606-
url "https://files.pythonhosted.org/packages/00/00/aaaa/pydantic-1.0.0.tar.gz"
611+
resource "baz" do
612+
url "https://files.pythonhosted.org/packages/00/00/aaaa/baz-1.0.0.tar.gz"
607613
sha256 "ghi789"
608614
end
609615
end
@@ -614,9 +620,9 @@ class Foo < Formula
614620
end
615621

616622
it "doesn't audit PyPI package if it is not a resource" do
617-
fa = formula_auditor "cryptography", <<~RUBY
618-
class Cryptography < Formula
619-
url "https://files.pythonhosted.org/packages/60/04/aaaa/cryptography-1.0.0.tar.gz"
623+
fa = formula_auditor("bar", <<~RUBY, tap_audit_exceptions: {}, pypi_dependencies_formulae:)
624+
class Bar < Formula
625+
url "https://files.pythonhosted.org/packages/00/00/aaaa/bar-1.0.0.tar.gz"
620626
sha256 "abc123"
621627
homepage "https://brew.sh"
622628
end

0 commit comments

Comments
 (0)