formula_auditor: create a versioned formula dependent conflict allowlist

We have an audit that checks each formula's dependency tree for multiple
versions of the same software. We have an allowlist that allows us to
ignore this audit, but this allowlist requires each formula with a
conflict in its dependency tree to be listed there.

Here, I propose the reverse: if formula `foo` appears in the
`versioned_formula_dependent_conflicts_allowlist`, then all its
dependents will not fail the versioned dependencies conflict because of
a conflict with formula `foo`.

I'd like to do this in the case of `python`, where I think the versioned
dependencies conflict check hurts us more than helps us. Versioned
dependency conflicts are most problematic in the case of libraries with
the same install name but incompatible ABIs. This is almost never a
problem with Python: almost no formulae link with the Python framework
on macOS (in part due to one of our audits that disallows Python
framework linkage in Python modules). Moreover, the various Python
frameworks that we ship have the version in the install name.

The above _might_ be a problem on Linux, since we allow unrestricted
linkage with `libpython`. However, we don't even check versioned
conflicts on Linux, so we aren't as concerned about this in the first
place.

This is also a lot more convenient than adding the dependents of some
Python formula one by one as they acquire conflicts due to changes in
other formulae.

I've also amended `tap_auditor` to allow the use of formula aliases in
an allowlist, to allow us to add `python` to this allowlist instead of
each individual versioned Python formula.

See also discussion at Homebrew/homebrew-core#108307.
This commit is contained in:
Carlo Cabrera 2022-08-18 15:27:23 +08:00
parent fcb30c1ead
commit 18722901ee
No known key found for this signature in database
GPG Key ID: C74D447FC549A1D0
2 changed files with 10 additions and 3 deletions

View File

@ -344,6 +344,10 @@ module Homebrew
recursive_runtime_formulae.each do |f|
name = f.name
unversioned_name, = name.split("@")
# Allow use of the full versioned name (e.g. `python@3.99`) or an unversioned alias (`python`).
next if formula.tap&.audit_exception :versioned_formula_dependent_conflicts_allowlist, name
next if formula.tap&.audit_exception :versioned_formula_dependent_conflicts_allowlist, unversioned_name
version_hash[unversioned_name] ||= Set.new
version_hash[unversioned_name] << name
next if version_hash[unversioned_name].length < 2

View File

@ -8,8 +8,8 @@ module Homebrew
class TapAuditor
extend T::Sig
attr_reader :name, :path, :formula_names, :cask_tokens, :tap_audit_exceptions, :tap_style_exceptions,
:tap_pypi_formula_mappings, :problems
attr_reader :name, :path, :formula_names, :formula_aliases, :cask_tokens,
:tap_audit_exceptions, :tap_style_exceptions, :tap_pypi_formula_mappings, :problems
sig { params(tap: Tap, strict: T.nilable(T::Boolean)).void }
def initialize(tap, strict:)
@ -21,6 +21,7 @@ module Homebrew
@tap_pypi_formula_mappings = tap.pypi_formula_mappings
@problems = []
@formula_aliases = tap.aliases
@formula_names = tap.formula_names.map do |formula_name|
formula_name.split("/").last
end
@ -68,7 +69,9 @@ module Homebrew
list = list.keys if list.is_a? Hash
invalid_formulae_casks = list.select do |formula_or_cask_name|
@formula_names.exclude?(formula_or_cask_name) && @cask_tokens.exclude?("#{@name}/#{formula_or_cask_name}")
formula_names.exclude?(formula_or_cask_name) &&
formula_aliases.exclude?(formula_or_cask_name) &&
cask_tokens.exclude?("#{@name}/#{formula_or_cask_name}")
end
return if invalid_formulae_casks.empty?