Add tests for retrieving formula based on dependents

Also, made sure to clear formula cache before
and after autoremoving packages.
This commit is contained in:
apainintheneck 2022-07-15 16:27:22 -07:00
parent fe83500617
commit cb91f8b665
4 changed files with 139 additions and 38 deletions

View File

@ -160,7 +160,7 @@ module Homebrew
cleanup = Cleanup.new(dry_run: dry_run) cleanup = Cleanup.new(dry_run: dry_run)
if cleanup.periodic_clean_due? if cleanup.periodic_clean_due?
cleanup.periodic_clean! cleanup.periodic_clean!
elsif f.latest_version_installed? && !cleanup.skip_clean_formula?(f) elsif f.latest_version_installed? && !Cleanup.skip_clean_formula?(f)
ohai "Running `brew cleanup #{f}`..." ohai "Running `brew cleanup #{f}`..."
puts_no_install_cleanup_disable_message_if_not_already! puts_no_install_cleanup_disable_message_if_not_already!
cleanup.cleanup_formula(f) cleanup.cleanup_formula(f)
@ -177,7 +177,7 @@ module Homebrew
@puts_no_install_cleanup_disable_message_if_not_already = true @puts_no_install_cleanup_disable_message_if_not_already = true
end end
def skip_clean_formula?(f) def self.skip_clean_formula?(f)
return false if Homebrew::EnvConfig.no_cleanup_formulae.blank? return false if Homebrew::EnvConfig.no_cleanup_formulae.blank?
skip_clean_formulae = Homebrew::EnvConfig.no_cleanup_formulae.split(",") skip_clean_formulae = Homebrew::EnvConfig.no_cleanup_formulae.split(",")
@ -215,7 +215,7 @@ module Homebrew
if args.empty? if args.empty?
Formula.installed Formula.installed
.sort_by(&:name) .sort_by(&:name)
.reject { |f| skip_clean_formula?(f) } .reject { |f| Cleanup.skip_clean_formula?(f) }
.each do |formula| .each do |formula|
cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false) cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false)
end end
@ -256,7 +256,7 @@ module Homebrew
nil nil
end end
if formula && skip_clean_formula?(formula) if formula && Cleanup.skip_clean_formula?(formula)
onoe "Refusing to clean #{formula} because it is listed in " \ onoe "Refusing to clean #{formula} because it is listed in " \
"#{Tty.bold}HOMEBREW_NO_CLEANUP_FORMULAE#{Tty.reset}!" "#{Tty.bold}HOMEBREW_NO_CLEANUP_FORMULAE#{Tty.reset}!"
elsif formula elsif formula
@ -264,8 +264,6 @@ module Homebrew
end end
cleanup_cask(cask) if cask cleanup_cask(cask) if cask
end end
Cleanup.autoremove(dry_run: dry_run?) if Homebrew::EnvConfig.autoremove?
end end
end end
@ -526,7 +524,17 @@ module Homebrew
end end
def self.autoremove(dry_run: false) def self.autoremove(dry_run: false)
removable_formulae = Formula.unused_formulae_with_no_dependents require "cask/caskroom"
# If this runs after install, uninstall, reinstall or upgrade,
# the cache of installed formulae may no longer be valid.
Formula.clear_cache unless dry_run
# Remove formulae listed in HOMEBREW_NO_CLEANUP_FORMULAE.
formulae = Formula.installed.reject(&method(:skip_clean_formula?))
casks = Cask::Caskroom.casks
removable_formulae = Formula.unused_formulae_with_no_dependents(formulae, casks)
return if removable_formulae.blank? return if removable_formulae.blank?
@ -541,6 +549,9 @@ module Homebrew
kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack) kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack)
Uninstall.uninstall_kegs(kegs_by_rack) Uninstall.uninstall_kegs(kegs_by_rack)
# The installed formula cache will be invalid after uninstalling.
Formula.clear_cache
end end
end end
end end

View File

@ -37,7 +37,7 @@ module Homebrew
def leaves def leaves
args = leaves_args.parse args = leaves_args.parse
leaves_list = Formula.installed_formulae_with_no_formula_dependents leaves_list = Formula.formulae_with_no_formula_dependents(Formula.installed)
leaves_list.select!(&method(:installed_on_request?)) if args.installed_on_request? leaves_list.select!(&method(:installed_on_request?)) if args.installed_on_request?
leaves_list.select!(&method(:installed_as_dependency?)) if args.installed_as_dependency? leaves_list.select!(&method(:installed_as_dependency?)) if args.installed_as_dependency?

View File

@ -1708,11 +1708,8 @@ class Formula
# An array of all installed {Formula} with {Cask} dependents. # An array of all installed {Formula} with {Cask} dependents.
# @private # @private
def self.installed_formulae_with_cask_dependents def self.formulae_with_cask_dependents(casks)
require "cask/caskroom" casks.flat_map { |cask| cask.depends_on[:formula] }
Cask::Caskroom.casks
.flat_map { |cask| cask.depends_on[:formula] }
.compact .compact
.map { |f| Formula[f] } .map { |f| Formula[f] }
.flat_map { |f| [f, *f.runtime_formula_dependencies].compact } .flat_map { |f| [f, *f.runtime_formula_dependencies].compact }
@ -1720,17 +1717,17 @@ class Formula
# An array of all installed {Formula} without {Formula} dependents # An array of all installed {Formula} without {Formula} dependents
# @private # @private
def self.installed_formulae_with_no_formula_dependents(formulae = installed) def self.formulae_with_no_formula_dependents(formulae)
return [] if formulae.blank? return [] if formulae.blank?
formulae - formulae.flat_map(&:runtime_formula_dependencies) formulae - formulae.flat_map(&:runtime_formula_dependencies)
end end
# Recursive function that returns an array of installed {Formula} without # Recursive function that returns an array of {Formula} without
# {Formula} dependents that weren't installed on request. # {Formula} dependents that weren't installed on request.
# @private # @private
def self.unused_formulae_with_no_formula_dependents(formulae) def self.unused_formulae_with_no_formula_dependents(formulae)
unused_formulae = installed_formulae_with_no_formula_dependents(formulae).reject do |f| unused_formulae = formulae_with_no_formula_dependents(formulae).reject do |f|
Tab.for_keg(f.any_installed_keg).installed_on_request Tab.for_keg(f.any_installed_keg).installed_on_request
end end
@ -1741,12 +1738,12 @@ class Formula
unused_formulae unused_formulae
end end
# An array of installed {Formula} without {Formula} or {Cask} # An array of {Formula} without {Formula} or {Cask}
# dependents that weren't installed on request. # dependents that weren't installed on request.
# @private # @private
def self.unused_formulae_with_no_dependents def self.unused_formulae_with_no_dependents(formulae, casks)
unused_formulae = unused_formulae_with_no_formula_dependents(installed) unused_formulae = unused_formulae_with_no_formula_dependents(formulae)
unused_formulae - installed_formulae_with_cask_dependents unused_formulae - formulae_with_cask_dependents(casks)
end end
def self.installed_with_alias_path(alias_path) def self.installed_with_alias_path(alias_path)

View File

@ -446,40 +446,133 @@ describe Formula do
end end
end end
describe "::installed_formulae_with_no_formula_dependents" do shared_context "with formulae for dependency testing" do
let(:formula_is_dep) do let(:formula_with_deps) do
formula "foo" do formula "zero" do
url "foo-1.1" url "zero-1.0"
end end
end end
let(:formula_with_deps) do let(:formula_is_dep1) do
formula "bar" do formula "one" do
url "bar-1.0" url "one-1.1"
end
end
let(:formula_is_dep2) do
formula "two" do
url "two-1.1"
end end
end end
let(:formulae) do let(:formulae) do
[ [
formula_with_deps, formula_with_deps,
formula_is_dep, formula_is_dep1,
formula_is_dep2,
] ]
end end
before do before do
allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep]) allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep1,
formula_is_dep2])
allow(formula_is_dep1).to receive(:runtime_formula_dependencies).and_return([formula_is_dep2])
end
end end
specify "without formulae parameter" do describe "::formulae_with_no_formula_dependents" do
allow(described_class).to receive(:installed).and_return(formulae) include_context "with formulae for dependency testing"
expect(described_class.installed_formulae_with_no_formula_dependents) it "filters out dependencies" do
expect(described_class.formulae_with_no_formula_dependents(formulae))
.to eq([formula_with_deps]) .to eq([formula_with_deps])
end end
end
specify "with formulae parameter" do describe "::unused_formulae_with_no_formula_dependents" do
expect(described_class.installed_formulae_with_no_formula_dependents(formulae)) include_context "with formulae for dependency testing"
.to eq([formula_with_deps])
let(:tab_from_keg) { double }
before do
allow(Tab).to receive(:for_keg).and_return(tab_from_keg)
end
specify "installed on request" do
allow(tab_from_keg).to receive(:installed_on_request).and_return(true)
expect(described_class.unused_formulae_with_no_formula_dependents(formulae))
.to eq([])
end
specify "not installed on request" do
allow(tab_from_keg).to receive(:installed_on_request).and_return(false)
expect(described_class.unused_formulae_with_no_formula_dependents(formulae))
.to eq(formulae)
end
end
shared_context "with formulae and casks for dependency testing" do
include_context "with formulae for dependency testing"
require "cask/cask_loader"
let(:cask_one_dep) do
Cask::CaskLoader.load(+<<-RUBY)
cask "red" do
depends_on formula: "two"
end
RUBY
end
let(:cask_multiple_deps) do
Cask::CaskLoader.load(+<<-RUBY)
cask "blue" do
depends_on formula: "zero"
end
RUBY
end
let(:cask_no_deps1) do
Cask::CaskLoader.load(+<<-RUBY)
cask "green" do
end
RUBY
end
let(:cask_no_deps2) do
Cask::CaskLoader.load(+<<-RUBY)
cask "purple" do
end
RUBY
end
let(:casks_no_deps) { [cask_no_deps1, cask_no_deps2] }
let(:casks_one_dep) { [cask_no_deps1, cask_no_deps2, cask_one_dep] }
let(:casks_multiple_deps) { [cask_no_deps1, cask_no_deps2, cask_multiple_deps] }
before do
allow(described_class).to receive("[]").with("zero").and_return(formula_with_deps)
allow(described_class).to receive("[]").with("one").and_return(formula_is_dep1)
allow(described_class).to receive("[]").with("two").and_return(formula_is_dep2)
end
end
describe "::formulae_with_cask_dependents" do
include_context "with formulae and casks for dependency testing"
specify "no dependents" do
expect(described_class.formulae_with_cask_dependents(casks_no_deps))
.to eq([])
end
specify "one dependent" do
expect(described_class.formulae_with_cask_dependents(casks_one_dep))
.to eq([formula_is_dep2])
end
specify "multiple dependents" do
expect(described_class.formulae_with_cask_dependents(casks_multiple_deps))
.to eq(formulae)
end end
end end