mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Move autoremove code to util and add tests
This commit is contained in:
parent
ae17d3cffd
commit
f068f74f55
@ -579,6 +579,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.autoremove(dry_run: false)
|
def self.autoremove(dry_run: false)
|
||||||
|
require "utils/autoremove"
|
||||||
require "cask/caskroom"
|
require "cask/caskroom"
|
||||||
|
|
||||||
# If this runs after install, uninstall, reinstall or upgrade,
|
# If this runs after install, uninstall, reinstall or upgrade,
|
||||||
@ -593,7 +594,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
casks = Cask::Caskroom.casks
|
casks = Cask::Caskroom.casks
|
||||||
|
|
||||||
removable_formulae = Formula.unused_formulae_with_no_dependents(formulae, casks)
|
removable_formulae = Utils::Autoremove.removable_formulae(formulae, casks)
|
||||||
|
|
||||||
return if removable_formulae.blank?
|
return if removable_formulae.blank?
|
||||||
|
|
||||||
|
@ -1844,55 +1844,6 @@ class Formula
|
|||||||
end.uniq(&:name)
|
end.uniq(&:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# An array of all installed {Formula} with {Cask} dependents.
|
|
||||||
# @private
|
|
||||||
def self.formulae_with_cask_dependents(casks)
|
|
||||||
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 runtime {Formula}
|
|
||||||
# dependents for bottles and without build {Formula} dependents
|
|
||||||
# for those built from source.
|
|
||||||
# @private
|
|
||||||
def self.formulae_with_no_formula_dependents(formulae)
|
|
||||||
return [] if formulae.blank?
|
|
||||||
|
|
||||||
formulae - formulae.each_with_object([]) do |formula, dependents|
|
|
||||||
dependents.concat(formula.runtime_formula_dependencies)
|
|
||||||
|
|
||||||
# Include build dependencies when the formula is not a bottle
|
|
||||||
unless Tab.for_keg(formula.any_installed_keg).poured_from_bottle
|
|
||||||
dependents.concat(formula.deps.select(&:build?).map(&:to_formula))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recursive function that returns an array of {Formula} without
|
|
||||||
# {Formula} dependents that weren't installed on request.
|
|
||||||
# @private
|
|
||||||
def self.unused_formulae_with_no_formula_dependents(formulae)
|
|
||||||
unused_formulae = formulae_with_no_formula_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 {Formula} without {Formula} or {Cask}
|
|
||||||
# dependents that weren't installed on request.
|
|
||||||
# @private
|
|
||||||
def self.unused_formulae_with_no_dependents(formulae, casks)
|
|
||||||
unused_formulae = unused_formulae_with_no_formula_dependents(formulae)
|
|
||||||
unused_formulae - formulae_with_cask_dependents(casks)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.installed_with_alias_path(alias_path)
|
def self.installed_with_alias_path(alias_path)
|
||||||
return [] if alias_path.nil?
|
return [] if alias_path.nil?
|
||||||
|
|
||||||
|
@ -450,136 +450,6 @@ describe Formula do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_context "with formulae for dependency testing" do
|
|
||||||
let(:formula_with_deps) do
|
|
||||||
formula "zero" do
|
|
||||||
url "zero-1.0"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:formula_is_dep1) do
|
|
||||||
formula "one" do
|
|
||||||
url "one-1.1"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:formula_is_dep2) do
|
|
||||||
formula "two" do
|
|
||||||
url "two-1.1"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:formulae) do
|
|
||||||
[
|
|
||||||
formula_with_deps,
|
|
||||||
formula_is_dep1,
|
|
||||||
formula_is_dep2,
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
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
|
|
||||||
|
|
||||||
describe "::formulae_with_no_formula_dependents" do
|
|
||||||
include_context "with formulae for dependency testing"
|
|
||||||
|
|
||||||
it "filters out dependencies" do
|
|
||||||
expect(described_class.formulae_with_no_formula_dependents(formulae))
|
|
||||||
.to eq([formula_with_deps])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "::unused_formulae_with_no_formula_dependents" do
|
|
||||||
include_context "with formulae for dependency testing"
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
describe "::inreplace" do
|
describe "::inreplace" do
|
||||||
specify "raises build error on failure" do
|
specify "raises build error on failure" do
|
||||||
f = formula do
|
f = formula do
|
||||||
|
162
Library/Homebrew/test/utils/autoremove_spec.rb
Normal file
162
Library/Homebrew/test/utils/autoremove_spec.rb
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "utils/autoremove"
|
||||||
|
|
||||||
|
describe Utils::Autoremove do
|
||||||
|
shared_context "with formulae for dependency testing" do
|
||||||
|
let(:formula_with_deps) do
|
||||||
|
formula "zero" do
|
||||||
|
url "zero-1.0"
|
||||||
|
|
||||||
|
depends_on "three" => :build
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:formula_is_dep1) do
|
||||||
|
formula "one" do
|
||||||
|
url "one-1.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:formula_is_dep2) do
|
||||||
|
formula "two" do
|
||||||
|
url "two-1.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:formula_is_build_dep) do
|
||||||
|
formula "three" do
|
||||||
|
url "three-1.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:formulae) do
|
||||||
|
[
|
||||||
|
formula_with_deps,
|
||||||
|
formula_is_dep1,
|
||||||
|
formula_is_dep2,
|
||||||
|
formula_is_build_dep,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:tab_from_keg) { double }
|
||||||
|
|
||||||
|
before do
|
||||||
|
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])
|
||||||
|
|
||||||
|
allow(Tab).to receive(:for_keg).and_return(tab_from_keg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::formulae_with_no_formula_dependents" do
|
||||||
|
include_context "with formulae for dependency testing"
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(Formulary).to receive(:factory).with("three").and_return(formula_is_build_dep)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when formulae are bottles" do
|
||||||
|
it "filters out runtime dependencies" do
|
||||||
|
allow(tab_from_keg).to receive(:poured_from_bottle).and_return(true)
|
||||||
|
expect(described_class.send(:formulae_with_no_formula_dependents, formulae))
|
||||||
|
.to eq([formula_with_deps, formula_is_build_dep])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when formulae are built from source" do
|
||||||
|
it "filters out runtime and build dependencies" do
|
||||||
|
allow(tab_from_keg).to receive(:poured_from_bottle).and_return(false)
|
||||||
|
expect(described_class.send(:formulae_with_no_formula_dependents, formulae))
|
||||||
|
.to eq([formula_with_deps])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::unused_formulae_with_no_formula_dependents" do
|
||||||
|
include_context "with formulae for dependency testing"
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(tab_from_keg).to receive(:poured_from_bottle).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "installed on request" do
|
||||||
|
allow(tab_from_keg).to receive(:installed_on_request).and_return(true)
|
||||||
|
expect(described_class.send(: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.send(:unused_formulae_with_no_formula_dependents, formulae))
|
||||||
|
.to match_array(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(Formula).to receive("[]").with("zero").and_return(formula_with_deps)
|
||||||
|
allow(Formula).to receive("[]").with("one").and_return(formula_is_dep1)
|
||||||
|
allow(Formula).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.send(:formulae_with_cask_dependents, casks_no_deps))
|
||||||
|
.to eq([])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "one dependent" do
|
||||||
|
expect(described_class.send(:formulae_with_cask_dependents, casks_one_dep))
|
||||||
|
.to eq([formula_is_dep2])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "multiple dependents" do
|
||||||
|
expect(described_class.send(:formulae_with_cask_dependents, casks_multiple_deps))
|
||||||
|
.to match_array([formula_with_deps, formula_is_dep1, formula_is_dep2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
68
Library/Homebrew/utils/autoremove.rb
Normal file
68
Library/Homebrew/utils/autoremove.rb
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Utils
|
||||||
|
# Helper function for finding autoremovable formulae.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
module Autoremove
|
||||||
|
module_function
|
||||||
|
|
||||||
|
# An array of all installed {Formula} with {Cask} dependents.
|
||||||
|
# @private
|
||||||
|
def formulae_with_cask_dependents(casks)
|
||||||
|
casks.flat_map { |cask| cask.depends_on[:formula] }
|
||||||
|
.compact
|
||||||
|
.map { |f| Formula[f] }
|
||||||
|
.flat_map { |f| [f, *f.runtime_formula_dependencies].compact }
|
||||||
|
end
|
||||||
|
private_class_method :formulae_with_cask_dependents
|
||||||
|
|
||||||
|
# An array of all installed {Formula} without runtime {Formula}
|
||||||
|
# dependents for bottles and without build {Formula} dependents
|
||||||
|
# for those built from source.
|
||||||
|
# @private
|
||||||
|
def formulae_with_no_formula_dependents(formulae)
|
||||||
|
return [] if formulae.blank?
|
||||||
|
|
||||||
|
dependents = []
|
||||||
|
formulae.each do |formula|
|
||||||
|
dependents += formula.runtime_formula_dependencies
|
||||||
|
|
||||||
|
# Ignore build dependencies when the formula is a bottle
|
||||||
|
next if Tab.for_keg(formula.any_installed_keg).poured_from_bottle
|
||||||
|
|
||||||
|
formula.deps.select(&:build?).each do |dep|
|
||||||
|
suppress(FormulaUnavailableError) { dependents << dep.to_formula }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
formulae - dependents
|
||||||
|
end
|
||||||
|
private_class_method :formulae_with_no_formula_dependents
|
||||||
|
|
||||||
|
# Recursive function that returns an array of {Formula} without
|
||||||
|
# {Formula} dependents that weren't installed on request.
|
||||||
|
# @private
|
||||||
|
def unused_formulae_with_no_formula_dependents(formulae)
|
||||||
|
unused_formulae = formulae_with_no_formula_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
|
||||||
|
private_class_method :unused_formulae_with_no_formula_dependents
|
||||||
|
|
||||||
|
# An array of {Formula} without {Formula} or {Cask}
|
||||||
|
# dependents that weren't installed on request and without
|
||||||
|
# build dependencies for {Formula} installed from source.
|
||||||
|
# @private
|
||||||
|
def removable_formulae(formulae, casks)
|
||||||
|
unused_formulae = unused_formulae_with_no_formula_dependents(formulae)
|
||||||
|
unused_formulae - formulae_with_cask_dependents(casks)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user