commit
2ac5cffd0d
50
Library/Homebrew/cmd/autoremove.rb
Normal file
50
Library/Homebrew/cmd/autoremove.rb
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "formula"
|
||||||
|
require "cli/parser"
|
||||||
|
require "uninstall"
|
||||||
|
|
||||||
|
module Homebrew
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def autoremove_args
|
||||||
|
Homebrew::CLI::Parser.new do
|
||||||
|
usage_banner <<~EOS
|
||||||
|
`autoremove` [<options>]
|
||||||
|
|
||||||
|
Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed.
|
||||||
|
EOS
|
||||||
|
switch "-n", "--dry-run",
|
||||||
|
description: "List what would be uninstalled, but do not actually uninstall anything."
|
||||||
|
named 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_removable_formulae(formulae)
|
||||||
|
removable_formulae = Formula.installed_formulae_with_no_dependents(formulae).reject do |f|
|
||||||
|
Tab.for_keg(f.any_installed_keg).installed_on_request
|
||||||
|
end
|
||||||
|
|
||||||
|
removable_formulae += get_removable_formulae(formulae - removable_formulae) if removable_formulae.present?
|
||||||
|
|
||||||
|
removable_formulae
|
||||||
|
end
|
||||||
|
|
||||||
|
def autoremove
|
||||||
|
args = autoremove_args.parse
|
||||||
|
|
||||||
|
removable_formulae = get_removable_formulae(Formula.installed)
|
||||||
|
return if removable_formulae.blank?
|
||||||
|
|
||||||
|
formulae_names = removable_formulae.map(&:full_name).sort
|
||||||
|
|
||||||
|
verb = args.dry_run? ? "Would uninstall" : "Uninstalling"
|
||||||
|
oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:"
|
||||||
|
puts formulae_names.join("\n")
|
||||||
|
return if args.dry_run?
|
||||||
|
|
||||||
|
kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack)
|
||||||
|
Uninstall.uninstall_kegs(kegs_by_rack)
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -2,7 +2,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "formula"
|
require "formula"
|
||||||
require "tab"
|
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
@ -23,9 +22,6 @@ module Homebrew
|
|||||||
def leaves
|
def leaves
|
||||||
leaves_args.parse
|
leaves_args.parse
|
||||||
|
|
||||||
installed = Formula.installed.sort
|
Formula.installed_formulae_with_no_dependents.map(&:full_name).sort.each(&method(:puts))
|
||||||
deps_of_installed = installed.flat_map(&:runtime_formula_dependencies)
|
|
||||||
leaves = installed.map(&:full_name) - deps_of_installed.map(&:full_name)
|
|
||||||
leaves.each(&method(:puts))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -8,6 +8,7 @@ require "migrator"
|
|||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
require "cask/cmd"
|
require "cask/cmd"
|
||||||
require "cask/cask_loader"
|
require "cask/cask_loader"
|
||||||
|
require "uninstall"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module_function
|
module_function
|
||||||
@ -54,76 +55,10 @@ module Homebrew
|
|||||||
kegs_by_rack = all_kegs.group_by(&:rack)
|
kegs_by_rack = all_kegs.group_by(&:rack)
|
||||||
end
|
end
|
||||||
|
|
||||||
handle_unsatisfied_dependents(kegs_by_rack,
|
Uninstall.uninstall_kegs(kegs_by_rack,
|
||||||
|
force: args.force?,
|
||||||
ignore_dependencies: args.ignore_dependencies?,
|
ignore_dependencies: args.ignore_dependencies?,
|
||||||
named_args: args.named)
|
named_args: args.named)
|
||||||
return if Homebrew.failed?
|
|
||||||
|
|
||||||
kegs_by_rack.each do |rack, kegs|
|
|
||||||
if args.force?
|
|
||||||
name = rack.basename
|
|
||||||
|
|
||||||
if rack.directory?
|
|
||||||
puts "Uninstalling #{name}... (#{rack.abv})"
|
|
||||||
kegs.each do |keg|
|
|
||||||
keg.unlink
|
|
||||||
keg.uninstall
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
rm_pin rack
|
|
||||||
else
|
|
||||||
kegs.each do |keg|
|
|
||||||
begin
|
|
||||||
f = Formulary.from_rack(rack)
|
|
||||||
if f.pinned?
|
|
||||||
onoe "#{f.full_name} is pinned. You must unpin it to uninstall."
|
|
||||||
next
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
keg.lock do
|
|
||||||
puts "Uninstalling #{keg}... (#{keg.abv})"
|
|
||||||
keg.unlink
|
|
||||||
keg.uninstall
|
|
||||||
rack = keg.rack
|
|
||||||
rm_pin rack
|
|
||||||
|
|
||||||
if rack.directory?
|
|
||||||
versions = rack.subdirs.map(&:basename)
|
|
||||||
puts "#{keg.name} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed."
|
|
||||||
puts "Run `brew uninstall --force #{keg.name}` to remove all versions."
|
|
||||||
end
|
|
||||||
|
|
||||||
next unless f
|
|
||||||
|
|
||||||
paths = f.pkgetc.find.map(&:to_s) if f.pkgetc.exist?
|
|
||||||
if paths.present?
|
|
||||||
puts
|
|
||||||
opoo <<~EOS
|
|
||||||
The following #{f.name} configuration files have not been removed!
|
|
||||||
If desired, remove them manually with `rm -rf`:
|
|
||||||
#{paths.sort.uniq.join("\n ")}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
unversioned_name = f.name.gsub(/@.+$/, "")
|
|
||||||
maybe_paths = Dir.glob("#{f.etc}/*#{unversioned_name}*")
|
|
||||||
maybe_paths -= paths if paths.present?
|
|
||||||
if maybe_paths.present?
|
|
||||||
puts
|
|
||||||
opoo <<~EOS
|
|
||||||
The following may be #{f.name} configuration files and have not been removed!
|
|
||||||
If desired, remove them manually with `rm -rf`:
|
|
||||||
#{maybe_paths.sort.uniq.join("\n ")}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return if casks.blank?
|
return if casks.blank?
|
||||||
|
|
||||||
@ -144,74 +79,4 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: false, named_args: [])
|
|
||||||
return if ignore_dependencies
|
|
||||||
|
|
||||||
all_kegs = kegs_by_rack.values.flatten(1)
|
|
||||||
check_for_dependents(all_kegs, named_args: named_args)
|
|
||||||
rescue MethodDeprecatedError
|
|
||||||
# Silently ignore deprecations when uninstalling.
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_dependents(kegs, named_args: [])
|
|
||||||
return false unless result = Keg.find_some_installed_dependents(kegs)
|
|
||||||
|
|
||||||
if Homebrew::EnvConfig.developer?
|
|
||||||
DeveloperDependentsMessage.new(*result, named_args: named_args).output
|
|
||||||
else
|
|
||||||
NondeveloperDependentsMessage.new(*result, named_args: named_args).output
|
|
||||||
end
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
class DependentsMessage
|
|
||||||
attr_reader :reqs, :deps, :named_args
|
|
||||||
|
|
||||||
def initialize(requireds, dependents, named_args: [])
|
|
||||||
@reqs = requireds
|
|
||||||
@deps = dependents
|
|
||||||
@named_args = named_args
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def sample_command
|
|
||||||
"brew uninstall --ignore-dependencies #{named_args.join(" ")}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def are_required_by_deps
|
|
||||||
"#{"is".pluralize(reqs.count)} required by #{deps.to_sentence}, " \
|
|
||||||
"which #{"is".pluralize(deps.count)} currently installed"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class DeveloperDependentsMessage < DependentsMessage
|
|
||||||
def output
|
|
||||||
opoo <<~EOS
|
|
||||||
#{reqs.to_sentence} #{are_required_by_deps}.
|
|
||||||
You can silence this warning with:
|
|
||||||
#{sample_command}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class NondeveloperDependentsMessage < DependentsMessage
|
|
||||||
def output
|
|
||||||
ofail <<~EOS
|
|
||||||
Refusing to uninstall #{reqs.to_sentence}
|
|
||||||
because #{"it".pluralize(reqs.count)} #{are_required_by_deps}.
|
|
||||||
You can override this and force removal with:
|
|
||||||
#{sample_command}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def rm_pin(rack)
|
|
||||||
Formulary.from_rack(rack).unpin
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1518,6 +1518,14 @@ class Formula
|
|||||||
end.uniq(&:name)
|
end.uniq(&:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# An array of all installed {Formula} without dependents
|
||||||
|
# @private
|
||||||
|
def self.installed_formulae_with_no_dependents(formulae = installed)
|
||||||
|
return [] if formulae.blank?
|
||||||
|
|
||||||
|
formulae - formulae.flat_map(&:runtime_formula_dependencies)
|
||||||
|
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?
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,7 @@ RSpec/MultipleDescribes:
|
|||||||
- 'cmd/--repository_spec.rb'
|
- 'cmd/--repository_spec.rb'
|
||||||
- 'cmd/--version_spec.rb'
|
- 'cmd/--version_spec.rb'
|
||||||
- 'cmd/analytics_spec.rb'
|
- 'cmd/analytics_spec.rb'
|
||||||
|
- 'cmd/autoremove_spec.rb'
|
||||||
- 'cmd/cleanup_spec.rb'
|
- 'cmd/cleanup_spec.rb'
|
||||||
- 'cmd/commands_spec.rb'
|
- 'cmd/commands_spec.rb'
|
||||||
- 'cmd/config_spec.rb'
|
- 'cmd/config_spec.rb'
|
||||||
|
|||||||
8
Library/Homebrew/test/cmd/autoremove_spec.rb
Normal file
8
Library/Homebrew/test/cmd/autoremove_spec.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cmd/shared_examples/args_parse"
|
||||||
|
|
||||||
|
describe "Homebrew.autoremove_args" do
|
||||||
|
it_behaves_like "parseable arguments"
|
||||||
|
end
|
||||||
@ -8,7 +8,20 @@ describe "Homebrew.leaves_args" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "brew leaves", :integration_test do
|
describe "brew leaves", :integration_test do
|
||||||
it "prints all Formulae that are not dependencies of other Formulae" do
|
context "when there are no installed Formulae" do
|
||||||
|
it "prints nothing" do
|
||||||
|
setup_test_formula "foo"
|
||||||
|
setup_test_formula "bar"
|
||||||
|
|
||||||
|
expect { brew "leaves" }
|
||||||
|
.to not_to_output.to_stdout
|
||||||
|
.and not_to_output.to_stderr
|
||||||
|
.and be_a_success
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there are only installed Formulae without dependencies" do
|
||||||
|
it "prints all installed Formulae" do
|
||||||
setup_test_formula "foo"
|
setup_test_formula "foo"
|
||||||
setup_test_formula "bar"
|
setup_test_formula "bar"
|
||||||
(HOMEBREW_CELLAR/"foo/0.1/somedir").mkpath
|
(HOMEBREW_CELLAR/"foo/0.1/somedir").mkpath
|
||||||
@ -19,3 +32,18 @@ describe "brew leaves", :integration_test do
|
|||||||
.and be_a_success
|
.and be_a_success
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when there are installed Formulae" do
|
||||||
|
it "prints all installed Formulae that are not dependencies of another installed Formula" do
|
||||||
|
setup_test_formula "foo"
|
||||||
|
setup_test_formula "bar"
|
||||||
|
(HOMEBREW_CELLAR/"foo/0.1/somedir").mkpath
|
||||||
|
(HOMEBREW_CELLAR/"bar/0.1/somedir").mkpath
|
||||||
|
|
||||||
|
expect { brew "leaves" }
|
||||||
|
.to output("bar\n").to_stdout
|
||||||
|
.and not_to_output.to_stderr
|
||||||
|
.and be_a_success
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@ -19,61 +19,3 @@ describe "brew uninstall", :integration_test do
|
|||||||
.and be_a_success
|
.and be_a_success
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe Homebrew do
|
|
||||||
let(:dependency) { formula("dependency") { url "f-1" } }
|
|
||||||
let(:dependent) do
|
|
||||||
formula("dependent") do
|
|
||||||
url "f-1"
|
|
||||||
depends_on "dependency"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:kegs_by_rack) { { dependency.rack => [Keg.new(dependency.latest_installed_prefix)] } }
|
|
||||||
|
|
||||||
before do
|
|
||||||
[dependency, dependent].each do |f|
|
|
||||||
f.latest_installed_prefix.mkpath
|
|
||||||
Keg.new(f.latest_installed_prefix).optlink
|
|
||||||
end
|
|
||||||
|
|
||||||
tab = Tab.empty
|
|
||||||
tab.homebrew_version = "1.1.6"
|
|
||||||
tab.tabfile = dependent.latest_installed_prefix/Tab::FILENAME
|
|
||||||
tab.runtime_dependencies = [
|
|
||||||
{ "full_name" => "dependency", "version" => "1" },
|
|
||||||
]
|
|
||||||
tab.write
|
|
||||||
|
|
||||||
stub_formula_loader dependency
|
|
||||||
stub_formula_loader dependent
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "::handle_unsatisfied_dependents" do
|
|
||||||
specify "when developer" do
|
|
||||||
ENV["HOMEBREW_DEVELOPER"] = "1"
|
|
||||||
|
|
||||||
expect {
|
|
||||||
described_class.handle_unsatisfied_dependents(kegs_by_rack)
|
|
||||||
}.to output(/Warning/).to_stderr
|
|
||||||
|
|
||||||
expect(described_class).not_to have_failed
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "when not developer" do
|
|
||||||
expect {
|
|
||||||
described_class.handle_unsatisfied_dependents(kegs_by_rack)
|
|
||||||
}.to output(/Error/).to_stderr
|
|
||||||
|
|
||||||
expect(described_class).to have_failed
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "when not developer and `ignore_dependencies` is true" do
|
|
||||||
expect {
|
|
||||||
described_class.handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: true)
|
|
||||||
}.not_to output.to_stderr
|
|
||||||
|
|
||||||
expect(described_class).not_to have_failed
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|||||||
@ -440,6 +440,43 @@ describe Formula do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "::installed_formulae_with_no_dependents" do
|
||||||
|
let(:formula_is_dep) do
|
||||||
|
formula "foo" do
|
||||||
|
url "foo-1.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:formula_with_deps) do
|
||||||
|
formula "bar" do
|
||||||
|
url "bar-1.0"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:formulae) do
|
||||||
|
[
|
||||||
|
formula_with_deps,
|
||||||
|
formula_is_dep,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "without formulae parameter" do
|
||||||
|
allow(described_class).to receive(:installed).and_return(formulae)
|
||||||
|
|
||||||
|
expect(described_class.installed_formulae_with_no_dependents)
|
||||||
|
.to eq([formula_with_deps])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "with formulae parameter" do
|
||||||
|
expect(described_class.installed_formulae_with_no_dependents(formulae))
|
||||||
|
.to eq([formula_with_deps])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "::installed_with_alias_path" do
|
describe "::installed_with_alias_path" do
|
||||||
specify "with alias path with nil" do
|
specify "with alias path with nil" do
|
||||||
expect(described_class.installed_with_alias_path(nil)).to be_empty
|
expect(described_class.installed_with_alias_path(nil)).to be_empty
|
||||||
|
|||||||
62
Library/Homebrew/test/uninstall_spec.rb
Normal file
62
Library/Homebrew/test/uninstall_spec.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "uninstall"
|
||||||
|
|
||||||
|
describe Homebrew::Uninstall do
|
||||||
|
let(:dependency) { formula("dependency") { url "f-1" } }
|
||||||
|
let(:dependent) do
|
||||||
|
formula("dependent") do
|
||||||
|
url "f-1"
|
||||||
|
depends_on "dependency"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:kegs_by_rack) { { dependency.rack => [Keg.new(dependency.latest_installed_prefix)] } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
[dependency, dependent].each do |f|
|
||||||
|
f.latest_installed_prefix.mkpath
|
||||||
|
Keg.new(f.latest_installed_prefix).optlink
|
||||||
|
end
|
||||||
|
|
||||||
|
tab = Tab.empty
|
||||||
|
tab.homebrew_version = "1.1.6"
|
||||||
|
tab.tabfile = dependent.latest_installed_prefix/Tab::FILENAME
|
||||||
|
tab.runtime_dependencies = [
|
||||||
|
{ "full_name" => "dependency", "version" => "1" },
|
||||||
|
]
|
||||||
|
tab.write
|
||||||
|
|
||||||
|
stub_formula_loader dependency
|
||||||
|
stub_formula_loader dependent
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::handle_unsatisfied_dependents" do
|
||||||
|
specify "when developer" do
|
||||||
|
ENV["HOMEBREW_DEVELOPER"] = "1"
|
||||||
|
|
||||||
|
expect {
|
||||||
|
described_class.handle_unsatisfied_dependents(kegs_by_rack)
|
||||||
|
}.to output(/Warning/).to_stderr
|
||||||
|
|
||||||
|
expect(Homebrew).not_to have_failed
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "when not developer" do
|
||||||
|
expect {
|
||||||
|
described_class.handle_unsatisfied_dependents(kegs_by_rack)
|
||||||
|
}.to output(/Error/).to_stderr
|
||||||
|
|
||||||
|
expect(Homebrew).to have_failed
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "when not developer and `ignore_dependencies` is true" do
|
||||||
|
expect {
|
||||||
|
described_class.handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: true)
|
||||||
|
}.not_to output.to_stderr
|
||||||
|
|
||||||
|
expect(Homebrew).not_to have_failed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
160
Library/Homebrew/uninstall.rb
Normal file
160
Library/Homebrew/uninstall.rb
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
# typed: true
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "keg"
|
||||||
|
require "formula"
|
||||||
|
|
||||||
|
module Homebrew
|
||||||
|
# Helper module for uninstalling kegs.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
module Uninstall
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def uninstall_kegs(kegs_by_rack, force: false, ignore_dependencies: false, named_args: [])
|
||||||
|
handle_unsatisfied_dependents(kegs_by_rack,
|
||||||
|
ignore_dependencies: ignore_dependencies,
|
||||||
|
named_args: named_args)
|
||||||
|
return if Homebrew.failed?
|
||||||
|
|
||||||
|
kegs_by_rack.each do |rack, kegs|
|
||||||
|
if force
|
||||||
|
name = rack.basename
|
||||||
|
|
||||||
|
if rack.directory?
|
||||||
|
puts "Uninstalling #{name}... (#{rack.abv})"
|
||||||
|
kegs.each do |keg|
|
||||||
|
keg.unlink
|
||||||
|
keg.uninstall
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rm_pin rack
|
||||||
|
else
|
||||||
|
kegs.each do |keg|
|
||||||
|
begin
|
||||||
|
f = Formulary.from_rack(rack)
|
||||||
|
if f.pinned?
|
||||||
|
onoe "#{f.full_name} is pinned. You must unpin it to uninstall."
|
||||||
|
next
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
keg.lock do
|
||||||
|
puts "Uninstalling #{keg}... (#{keg.abv})"
|
||||||
|
keg.unlink
|
||||||
|
keg.uninstall
|
||||||
|
rack = keg.rack
|
||||||
|
rm_pin rack
|
||||||
|
|
||||||
|
if rack.directory?
|
||||||
|
versions = rack.subdirs.map(&:basename)
|
||||||
|
puts "#{keg.name} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed."
|
||||||
|
puts "Run `brew uninstall --force #{keg.name}` to remove all versions."
|
||||||
|
end
|
||||||
|
|
||||||
|
next unless f
|
||||||
|
|
||||||
|
paths = f.pkgetc.find.map(&:to_s) if f.pkgetc.exist?
|
||||||
|
if paths.present?
|
||||||
|
puts
|
||||||
|
opoo <<~EOS
|
||||||
|
The following #{f.name} configuration files have not been removed!
|
||||||
|
If desired, remove them manually with `rm -rf`:
|
||||||
|
#{paths.sort.uniq.join("\n ")}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
unversioned_name = f.name.gsub(/@.+$/, "")
|
||||||
|
maybe_paths = Dir.glob("#{f.etc}/*#{unversioned_name}*")
|
||||||
|
maybe_paths -= paths if paths.present?
|
||||||
|
if maybe_paths.present?
|
||||||
|
puts
|
||||||
|
opoo <<~EOS
|
||||||
|
The following may be #{f.name} configuration files and have not been removed!
|
||||||
|
If desired, remove them manually with `rm -rf`:
|
||||||
|
#{maybe_paths.sort.uniq.join("\n ")}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: false, named_args: [])
|
||||||
|
return if ignore_dependencies
|
||||||
|
|
||||||
|
all_kegs = kegs_by_rack.values.flatten(1)
|
||||||
|
check_for_dependents(all_kegs, named_args: named_args)
|
||||||
|
rescue MethodDeprecatedError
|
||||||
|
# Silently ignore deprecations when uninstalling.
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_for_dependents(kegs, named_args: [])
|
||||||
|
return false unless result = Keg.find_some_installed_dependents(kegs)
|
||||||
|
|
||||||
|
if Homebrew::EnvConfig.developer?
|
||||||
|
DeveloperDependentsMessage.new(*result, named_args: named_args).output
|
||||||
|
else
|
||||||
|
NondeveloperDependentsMessage.new(*result, named_args: named_args).output
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
class DependentsMessage
|
||||||
|
attr_reader :reqs, :deps, :named_args
|
||||||
|
|
||||||
|
def initialize(requireds, dependents, named_args: [])
|
||||||
|
@reqs = requireds
|
||||||
|
@deps = dependents
|
||||||
|
@named_args = named_args
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def sample_command
|
||||||
|
"brew uninstall --ignore-dependencies #{named_args.join(" ")}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def are_required_by_deps
|
||||||
|
"#{"is".pluralize(reqs.count)} required by #{deps.to_sentence}, " \
|
||||||
|
"which #{"is".pluralize(deps.count)} currently installed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
class DeveloperDependentsMessage < DependentsMessage
|
||||||
|
def output
|
||||||
|
opoo <<~EOS
|
||||||
|
#{reqs.to_sentence} #{are_required_by_deps}.
|
||||||
|
You can silence this warning with:
|
||||||
|
#{sample_command}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
class NondeveloperDependentsMessage < DependentsMessage
|
||||||
|
def output
|
||||||
|
ofail <<~EOS
|
||||||
|
Refusing to uninstall #{reqs.to_sentence}
|
||||||
|
because #{"it".pluralize(reqs.count)} #{are_required_by_deps}.
|
||||||
|
You can override this and force removal with:
|
||||||
|
#{sample_command}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def rm_pin(rack)
|
||||||
|
Formulary.from_rack(rack).unpin
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
7
Library/Homebrew/uninstall.rbi
Normal file
7
Library/Homebrew/uninstall.rbi
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# typed: strict
|
||||||
|
|
||||||
|
module Homebrew
|
||||||
|
module Uninstall
|
||||||
|
include Kernel
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -12,6 +12,7 @@
|
|||||||
abv
|
abv
|
||||||
analytics
|
analytics
|
||||||
audit
|
audit
|
||||||
|
autoremove
|
||||||
bottle
|
bottle
|
||||||
bump
|
bump
|
||||||
bump-cask-pr
|
bump-cask-pr
|
||||||
|
|||||||
@ -56,6 +56,13 @@ Turn Homebrew's analytics on or off respectively.
|
|||||||
`brew analytics regenerate-uuid`:
|
`brew analytics regenerate-uuid`:
|
||||||
Regenerate the UUID used for Homebrew's analytics.
|
Regenerate the UUID used for Homebrew's analytics.
|
||||||
|
|
||||||
|
### `autoremove` [*`options`*]
|
||||||
|
|
||||||
|
Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed.
|
||||||
|
|
||||||
|
* `-n`, `--dry-run`:
|
||||||
|
List what would be uninstalled, but do not actually uninstall anything.
|
||||||
|
|
||||||
### `cask` *`command`* [*`options`*] [*`cask`*]
|
### `cask` *`command`* [*`options`*] [*`cask`*]
|
||||||
|
|
||||||
Homebrew Cask provides a friendly CLI workflow for the administration of macOS applications distributed as binaries.
|
Homebrew Cask provides a friendly CLI workflow for the administration of macOS applications distributed as binaries.
|
||||||
|
|||||||
@ -53,6 +53,13 @@ Control Homebrew\'s anonymous aggregate user behaviour analytics\. Read more at
|
|||||||
\fBbrew analytics regenerate\-uuid\fR
|
\fBbrew analytics regenerate\-uuid\fR
|
||||||
Regenerate the UUID used for Homebrew\'s analytics\.
|
Regenerate the UUID used for Homebrew\'s analytics\.
|
||||||
.
|
.
|
||||||
|
.SS "\fBautoremove\fR [\fIoptions\fR]"
|
||||||
|
Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed\.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\fB\-n\fR, \fB\-\-dry\-run\fR
|
||||||
|
List what would be uninstalled, but do not actually uninstall anything\.
|
||||||
|
.
|
||||||
.SS "\fBcask\fR \fIcommand\fR [\fIoptions\fR] [\fIcask\fR]"
|
.SS "\fBcask\fR \fIcommand\fR [\fIoptions\fR] [\fIcask\fR]"
|
||||||
Homebrew Cask provides a friendly CLI workflow for the administration of macOS applications distributed as binaries\.
|
Homebrew Cask provides a friendly CLI workflow for the administration of macOS applications distributed as binaries\.
|
||||||
.
|
.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user