From fa8ada31b88088e05f8438b3ed04337a470d0971 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Thu, 23 Jan 2025 14:45:17 +0000 Subject: [PATCH] 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. --- Library/Homebrew/cleanup.rb | 16 ++++++++++++++++ Library/Homebrew/test/cleanup_spec.rb | 2 ++ 2 files changed, 18 insertions(+) diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb index 00ca1e00d0..68b22eb204 100644 --- a/Library/Homebrew/cleanup.rb +++ b/Library/Homebrew/cleanup.rb @@ -101,6 +101,15 @@ module Homebrew package.tap_git_head != git_head 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) } def stale_formula?(pathname, scrub) return false unless HOMEBREW_CELLAR.directory? @@ -131,6 +140,7 @@ module Homebrew nil end + formula_excluded_versions_from_cleanup = nil if formula.blank? && formula_name.delete_suffix!("_bottle_manifest") formula = begin Formulary.from_rack(HOMEBREW_CELLAR/formula_name) @@ -140,6 +150,9 @@ module Homebrew 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. return false unless formula.latest_version_installed? @@ -158,6 +171,9 @@ module Homebrew return true unless patch_hashes&.include?(Checksum.new(version.to_s)) elsif resource_name && stable && (resource_version = stable.resources[resource_name]&.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) || formula.pkg_version.to_s > version return true diff --git a/Library/Homebrew/test/cleanup_spec.rb b/Library/Homebrew/test/cleanup_spec.rb index e622a1d8be..ab97061c8d 100644 --- a/Library/Homebrew/test/cleanup_spec.rb +++ b/Library/Homebrew/test/cleanup_spec.rb @@ -417,6 +417,8 @@ RSpec.describe Homebrew::Cleanup do FileUtils.touch testball FileUtils.touch testball_resource (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")) end