From 18722901eeceff0b26c34a257a493ee1bfb78a70 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera <30379873+carlocab@users.noreply.github.com> Date: Thu, 18 Aug 2022 15:27:23 +0800 Subject: [PATCH] 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. --- Library/Homebrew/formula_auditor.rb | 4 ++++ Library/Homebrew/tap_auditor.rb | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index bb6507fefa..a08bb73d26 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -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 diff --git a/Library/Homebrew/tap_auditor.rb b/Library/Homebrew/tap_auditor.rb index d946a12e27..16bd6e1444 100644 --- a/Library/Homebrew/tap_auditor.rb +++ b/Library/Homebrew/tap_auditor.rb @@ -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?