cleanup: improve cleanup version detection.

We're using `formula.eligible_kegs_for_cleanup` to figure out which
formula should be kept or removed based on e.g. `brew pin` status but
we didn't use this sufficiently in `brew cleanup` to avoid cleaning up
all cached files related to a pinned keg.

Instead, let's use a (cached) call to
`formula.eligible_kegs_for_cleanup` to ensure that we check all
related resources, manifests, etc. for pinned bottles rather than just
the latest version.
This commit is contained in:
Mike McQuaid 2025-01-23 14:45:17 +00:00
parent a3b0f9e536
commit fa8ada31b8
No known key found for this signature in database
2 changed files with 18 additions and 0 deletions

View File

@ -101,6 +101,15 @@ module Homebrew
package.tap_git_head != git_head package.tap_git_head != git_head
end end
sig { params(formula: Formula).returns(T::Set[String]) }
def excluded_versions_from_cleanup(formula)
@excluded_versions_from_cleanup ||= {}
@excluded_versions_from_cleanup[formula.name] ||= begin
eligible_kegs_for_cleanup = formula.eligible_kegs_for_cleanup(quiet: true)
Set.new((formula.installed_kegs - eligible_kegs_for_cleanup).map { |keg| keg.version.to_s })
end
end
sig { params(pathname: Pathname, scrub: T::Boolean).returns(T::Boolean) } sig { params(pathname: Pathname, scrub: T::Boolean).returns(T::Boolean) }
def stale_formula?(pathname, scrub) def stale_formula?(pathname, scrub)
return false unless HOMEBREW_CELLAR.directory? return false unless HOMEBREW_CELLAR.directory?
@ -131,6 +140,7 @@ module Homebrew
nil nil
end end
formula_excluded_versions_from_cleanup = nil
if formula.blank? && formula_name.delete_suffix!("_bottle_manifest") if formula.blank? && formula_name.delete_suffix!("_bottle_manifest")
formula = begin formula = begin
Formulary.from_rack(HOMEBREW_CELLAR/formula_name) Formulary.from_rack(HOMEBREW_CELLAR/formula_name)
@ -140,6 +150,9 @@ module Homebrew
return false if formula.blank? return false if formula.blank?
formula_excluded_versions_from_cleanup = excluded_versions_from_cleanup(formula)
return false if formula_excluded_versions_from_cleanup.include?(version.to_s)
# We can't determine an installed rebuild and parsing manifest version cannot be reliably done. # We can't determine an installed rebuild and parsing manifest version cannot be reliably done.
return false unless formula.latest_version_installed? return false unless formula.latest_version_installed?
@ -158,6 +171,9 @@ module Homebrew
return true unless patch_hashes&.include?(Checksum.new(version.to_s)) return true unless patch_hashes&.include?(Checksum.new(version.to_s))
elsif resource_name && stable && (resource_version = stable.resources[resource_name]&.version) elsif resource_name && stable && (resource_version = stable.resources[resource_name]&.version)
return true if resource_version != version return true if resource_version != version
elsif (formula_excluded_versions_from_cleanup ||= excluded_versions_from_cleanup(formula).presence) &&
formula_excluded_versions_from_cleanup.include?(version.to_s)
return false
elsif (formula.latest_version_installed? && formula.pkg_version.to_s != version) || elsif (formula.latest_version_installed? && formula.pkg_version.to_s != version) ||
formula.pkg_version.to_s > version formula.pkg_version.to_s > version
return true return true

View File

@ -417,6 +417,8 @@ RSpec.describe Homebrew::Cleanup do
FileUtils.touch testball FileUtils.touch testball
FileUtils.touch testball_resource FileUtils.touch testball_resource
(HOMEBREW_CELLAR/"testball"/"0.0.1").mkpath (HOMEBREW_CELLAR/"testball"/"0.0.1").mkpath
# Create the latest version of testball so the older version is eligible for cleanup.
(HOMEBREW_CELLAR/"testball"/"0.1/bin").mkpath
FileUtils.touch(CoreTap.instance.new_formula_path("testball")) FileUtils.touch(CoreTap.instance.new_formula_path("testball"))
end end