Module: Homebrew::Uninstall Private

Extended by:
Utils::Output::Mixin
Defined in:
uninstall.rb

Overview

This module is part of a private API. This module may only be used in the Homebrew/brew repository. Third parties should avoid using this module if possible, as it may be removed or changed without warning.

Helper module for uninstalling kegs.

Class Method Summary collapse

Methods included from Utils::Output::Mixin

issue_reporting_message, odebug, odeprecated, odie, odisabled, ofail, oh1, oh1_title, ohai, ohai_title, onoe, opoo, opoo_once, opoo_outside_github_actions, opoo_without_github_actions_annotation, pretty_cannot_install, pretty_deprecated, pretty_disabled, pretty_duration, pretty_install_status, pretty_installed, pretty_removed, pretty_uninstalled, pretty_unmarked, pretty_upgradable, pretty_warning

Class Method Details

.check_for_dependents!(kegs, casks: [], named_args: []) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


169
170
171
172
173
174
# File 'uninstall.rb', line 169

def self.check_for_dependents!(kegs, casks: [], named_args: [])
  return false unless (result = InstalledDependents.find_some_installed_dependents(kegs, casks:))

  DependentsMessage.new(*result, named_args:).output
  true
end

.handle_unsatisfied_dependents(kegs_by_rack, casks: [], ignore_dependencies: false, named_args: []) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.

Parameters:



158
159
160
161
162
163
164
165
166
# File 'uninstall.rb', line 158

def self.handle_unsatisfied_dependents(kegs_by_rack, casks: [], ignore_dependencies: false, named_args: [])
  return if ignore_dependencies

  all_kegs = kegs_by_rack.values.flatten(1)
  check_for_dependents!(all_kegs, casks:, named_args:)
rescue MethodDeprecatedError
  # Silently ignore deprecations when uninstalling.
  nil
end

.rm_pin(rack) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.

Parameters:



177
178
179
180
181
# File 'uninstall.rb', line 177

def self.rm_pin(rack)
  Formulary.from_rack(rack).unpin
rescue
  nil
end

.uninstall_kegs(kegs_by_rack, casks: [], force: false, ignore_dependencies: false, named_args: [], dry_run: false) ⇒ Array<Keg>?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

  • kegs_by_rack (Hash{Pathname => Array<Keg>})
  • casks (Array<Cask::Cask>) (defaults to: [])
  • force (Boolean) (defaults to: false)
  • ignore_dependencies (Boolean) (defaults to: false)
  • named_args (Array<String>) (defaults to: [])
  • dry_run (Boolean) (defaults to: false)

Returns:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'uninstall.rb', line 25

def self.uninstall_kegs(kegs_by_rack, casks: [], force: false, ignore_dependencies: false, named_args: [],
                        dry_run: false)
  kegs_to_uninstall = []
  handle_unsatisfied_dependents(kegs_by_rack,
                                casks:,
                                ignore_dependencies:,
                                named_args:)
  return if Homebrew.failed?

  kegs_by_rack.each do |rack, kegs|
    if force
      name = rack.basename

      if rack.directory?
        if dry_run
          kegs.each do |keg|
            puts "Would uninstall #{keg.name} #{keg.version}"
            kegs_to_uninstall << keg
            keg.unlink(dry_run: true)
            keg.uninstall(dry_run: true)
          end
        else
          puts "Uninstalling #{name}... (#{rack.abv})"
          kegs.each do |keg|
            kegs_to_uninstall << keg
            keg.unlink
            keg.uninstall
          end
        end
      end

      rm_pin rack unless dry_run
    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."
            break # exit keg loop and move on to next rack
          end
        rescue
          nil
        end

        keg.lock do
          if dry_run
            puts "Would uninstall #{keg.name} #{keg.version}"
            kegs_to_uninstall << keg
            keg.unlink(dry_run: true)
            keg.uninstall(dry_run: true)
            next
          end

          puts "Uninstalling #{keg}... (#{keg.abv})"
          kegs_to_uninstall << keg
          keg.unlink
          keg.uninstall
          rack = keg.rack
          rm_pin rack

          if rack.directory?
            versions = rack.subdirs.map(&:basename)
            puts <<~EOS
              #{keg.name} #{Utils::Text.to_sentence(versions)} #{versions.one? ? "is" : "are"} still installed.
              To remove all versions, run:
                brew uninstall --force #{keg.name}
            EOS
          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}*")
          excluded_names = if Homebrew::EnvConfig.no_install_from_api?
            Formula.names
          else
            Homebrew::API.formula_names
          end.to_set
          maybe_paths = maybe_paths.reject do |path|
            # Remove extension only if a file
            # (e.g. directory with name "openssl@1.1" will be trimmed to "openssl@1")
            basename = if File.directory?(path)
              File.basename(path)
            else
              File.basename(path, ".*")
            end
            excluded_names.include?(basename)
          end
          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
  kegs_to_uninstall
rescue MultipleVersionsInstalledError => e
  ofail e
  nil
ensure
  # If we delete Cellar/newname, then Cellar/oldname symlink
  # can become broken and we have to remove it.
  if !dry_run && HOMEBREW_CELLAR.directory?
    HOMEBREW_CELLAR.children.each do |rack|
      rack.unlink if rack.symlink? && !Utils::Path.resolved_path_exists?(rack)
    end
  end
end