Moved autoremove logic into autoremove.rb

This allows us to call that logic internally in other brew
commands instead of having to shell out.
This commit is contained in:
apainintheneck 2022-07-13 11:46:43 -07:00
parent 74f7b604cd
commit fa43418bfb
9 changed files with 77 additions and 52 deletions

View File

@ -0,0 +1,64 @@
# typed: false
# frozen_string_literal: true
require "cask/caskroom"
require "formula"
require "uninstall"
module Homebrew
# Helpers for removing unused formulae.
#
# @api private
module Autoremove
module_function
def remove_unused_formulae(dry_run: false)
removable_formulae = unused_formulae_with_no_dependents
return if removable_formulae.blank?
formulae_names = removable_formulae.map(&:full_name).sort
verb = dry_run ? "Would autoremove" : "Autoremoving"
oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:"
puts formulae_names.join("\n")
return if dry_run
kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack)
Uninstall.uninstall_kegs(kegs_by_rack)
end
# An array of installed {Formula} without {Formula} or {Cask}
# dependents that weren't installed on request.
# @private
def unused_formulae_with_no_dependents
unused_formulae = unused_formulae_with_no_formula_dependents(Formula.installed)
unused_formulae - installed_formulae_with_cask_dependents
end
# Recursive function that returns an array of installed {Formula} without
# {Formula} dependents that weren't installed on request.
# @private
def unused_formulae_with_no_formula_dependents(formulae)
unused_formulae = Formula.installed_formulae_with_no_dependents(formulae).reject do |f|
Tab.for_keg(f.any_installed_keg).installed_on_request
end
if unused_formulae.present?
unused_formulae += unused_formulae_with_no_formula_dependents(formulae - unused_formulae)
end
unused_formulae
end
# An array of all installed {Formula} with {Cask} dependents.
# @private
def installed_formulae_with_cask_dependents
Cask::Caskroom.casks
.flat_map { |cask| cask.depends_on[:formula] }
.compact
.map { |f| Formula[f] }
.flat_map { |f| [f, *f.runtime_formula_dependencies].compact }
end
end
end

View File

@ -1,9 +1,8 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "formula" require "autoremove"
require "cli/parser" require "cli/parser"
require "uninstall"
module Homebrew module Homebrew
module_function module_function
@ -23,6 +22,6 @@ module Homebrew
def autoremove def autoremove
args = autoremove_args.parse args = autoremove_args.parse
Uninstall.autoremove_kegs(Formula.removable_formulae, dry_run: args.dry_run?) Autoremove.remove_unused_formulae(dry_run: args.dry_run?)
end end
end end

View File

@ -1,6 +1,7 @@
# typed: false # typed: false
# frozen_string_literal: true # frozen_string_literal: true
require "autoremove"
require "cask/config" require "cask/config"
require "cask/cmd" require "cask/cmd"
require "cask/cmd/install" require "cask/cmd/install"
@ -254,6 +255,8 @@ module Homebrew
) )
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
Autoremove.remove_unused_formulae if Homebrew::EnvConfig.autoremove?
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e TapFormulaUnreadableError, TapFormulaClassUnavailableError => e
# Need to rescue before `FormulaUnavailableError` (superclass of this) # Need to rescue before `FormulaUnavailableError` (superclass of this)

View File

@ -1,6 +1,7 @@
# typed: false # typed: false
# frozen_string_literal: true # frozen_string_literal: true
require "autoremove"
require "formula_installer" require "formula_installer"
require "development_tools" require "development_tools"
require "messages" require "messages"
@ -152,5 +153,7 @@ module Homebrew
end end
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
Autoremove.remove_unused_formulae if Homebrew::EnvConfig.autoremove?
end end
end end

View File

@ -79,8 +79,6 @@ module Homebrew
) )
end end
return unless Homebrew::EnvConfig.uninstall_autoremove? Autoremove.remove_unused_formulae if Homebrew::EnvConfig.autoremove?
Uninstall.autoremove_kegs(Formula.removable_formulae)
end end
end end

View File

@ -1,6 +1,7 @@
# typed: false # typed: false
# frozen_string_literal: true # frozen_string_literal: true
require "autoremove"
require "cli/parser" require "cli/parser"
require "formula_installer" require "formula_installer"
require "install" require "install"
@ -111,6 +112,8 @@ module Homebrew
upgrade_outdated_casks(casks, args: args) unless only_upgrade_formulae upgrade_outdated_casks(casks, args: args) unless only_upgrade_formulae
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
Autoremove.remove_unused_formulae(dry_run: args.dry_run?) if Homebrew::EnvConfig.autoremove?
end end
sig { params(formulae: T::Array[Formula], args: CLI::Args).returns(T::Boolean) } sig { params(formulae: T::Array[Formula], args: CLI::Args).returns(T::Boolean) }

View File

@ -36,7 +36,7 @@ module Homebrew
"disable auto-update entirely with HOMEBREW_NO_AUTO_UPDATE.", "disable auto-update entirely with HOMEBREW_NO_AUTO_UPDATE.",
default: 300, default: 300,
}, },
HOMEBREW_AUTOREMOVE: { HOMEBREW_AUTOREMOVE: {
description: "If set, calls to `brew install`, `brew upgrade`, `brew reinstall` and `brew uninstall` " \ description: "If set, calls to `brew install`, `brew upgrade`, `brew reinstall` and `brew uninstall` " \
"will automatically remove unused formula dependents.", "will automatically remove unused formula dependents.",
boolean: true, boolean: true,

View File

@ -1720,37 +1720,6 @@ class Formula
installed.select { |f| f.installed_alias_path == alias_path } installed.select { |f| f.installed_alias_path == alias_path }
end end
# An array of all installed {Formula} with {Cask} dependents.
# @private
def self.installed_formulae_with_cask_dependents
Cask::Caskroom.casks
.flat_map { |cask| cask.depends_on[:formula] }
.compact
.map { |f| Formula[f] }
.flat_map { |f| [f, *f.runtime_formula_dependencies].compact }
end
# An array of all installed {Formula} without {Formula} or {Cask} dependents
# that weren't installed on request.
# @private
def self.removable_formulae
formulae = installed
all_removable_formulae = T.let([], T::Array[Formula])
loop do
removable_formulae = installed_formulae_with_no_dependents(formulae).reject do |f|
Tab.for_keg(f.any_installed_keg).installed_on_request
end
break if removable_formulae.blank?
all_removable_formulae += removable_formulae
formulae -= removable_formulae
end
all_removable_formulae - installed_formulae_with_cask_dependents
end
# an array of all alias files of core {Formula} # an array of all alias files of core {Formula}
# @private # @private
def self.core_alias_files def self.core_alias_files

View File

@ -97,20 +97,6 @@ module Homebrew
end end
end end
def autoremove_kegs(removable_formulae, dry_run: false)
return if removable_formulae.blank?
formulae_names = removable_formulae.map(&:full_name).sort
verb = dry_run ? "Would uninstall" : "Uninstalling"
oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:"
puts formulae_names.join("\n")
return if dry_run
kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack)
Uninstall.uninstall_kegs(kegs_by_rack)
end
def handle_unsatisfied_dependents(kegs_by_rack, casks: [], ignore_dependencies: false, named_args: []) def handle_unsatisfied_dependents(kegs_by_rack, casks: [], ignore_dependencies: false, named_args: [])
return if ignore_dependencies return if ignore_dependencies