Add brew zap command.
				
					
				
			This commit is contained in:
		
							parent
							
								
									181baaafb0
								
							
						
					
					
						commit
						f4b4fdac98
					
				@ -32,6 +32,15 @@ module Cask
 | 
			
		||||
 | 
			
		||||
      sig { void }
 | 
			
		||||
      def run
 | 
			
		||||
        self.class.zap_casks(*casks, verbose: args.verbose?, force: args.force?)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(casks: Cask, force: T.nilable(T::Boolean), verbose: T.nilable(T::Boolean)).void }
 | 
			
		||||
      def self.zap_casks(
 | 
			
		||||
        *casks,
 | 
			
		||||
        force: nil,
 | 
			
		||||
        verbose: nil
 | 
			
		||||
      )
 | 
			
		||||
        require "cask/installer"
 | 
			
		||||
 | 
			
		||||
        casks.each do |cask|
 | 
			
		||||
@ -43,10 +52,10 @@ module Cask
 | 
			
		||||
              cask = CaskLoader.load(installed_caskfile)
 | 
			
		||||
            end
 | 
			
		||||
          else
 | 
			
		||||
            raise CaskNotInstalledError, cask unless args.force?
 | 
			
		||||
            raise CaskNotInstalledError, cask unless force
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          Installer.new(cask, verbose: args.verbose?, force: args.force?).zap
 | 
			
		||||
          Installer.new(cask, verbose: verbose, force: force).zap
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -35,10 +35,10 @@ module Homebrew
 | 
			
		||||
        @to_formulae ||= to_formulae_and_casks(only: :formula).freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_formulae_and_casks(only: nil, method: nil)
 | 
			
		||||
      def to_formulae_and_casks(only: nil, ignore_unavailable: nil, method: nil)
 | 
			
		||||
        @to_formulae_and_casks ||= {}
 | 
			
		||||
        @to_formulae_and_casks[only] ||= begin
 | 
			
		||||
          to_objects(only: only, method: method).reject { |o| o.is_a?(Tap) }.freeze
 | 
			
		||||
          to_objects(only: only, ignore_unavailable: ignore_unavailable, method: method).freeze
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,10 @@ module Homebrew
 | 
			
		||||
        end.uniq.freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig do
 | 
			
		||||
        params(name: String, only: T.nilable(Symbol), method: T.nilable(Symbol))
 | 
			
		||||
          .returns(T.any(Formula, Cask::Cask, Keg, T::Array[Keg]))
 | 
			
		||||
      end
 | 
			
		||||
      def load_formula_or_cask(name, only: nil, method: nil)
 | 
			
		||||
        if only != :cask
 | 
			
		||||
          begin
 | 
			
		||||
@ -68,6 +72,9 @@ module Homebrew
 | 
			
		||||
              resolve_formula(name)
 | 
			
		||||
            when :keg
 | 
			
		||||
              resolve_keg(name)
 | 
			
		||||
            when :kegs
 | 
			
		||||
              rack = Formulary.to_rack(name)
 | 
			
		||||
              rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
 | 
			
		||||
            else
 | 
			
		||||
              raise
 | 
			
		||||
            end
 | 
			
		||||
@ -108,10 +115,12 @@ module Homebrew
 | 
			
		||||
      # Convert named arguments to {Formula} or {Cask} objects.
 | 
			
		||||
      # If both a formula and cask exist with the same name, returns the
 | 
			
		||||
      # formula and prints a warning unless `only` is specified.
 | 
			
		||||
      def to_objects(only: nil, method: nil)
 | 
			
		||||
      def to_objects(only: nil, ignore_unavailable: nil, method: nil)
 | 
			
		||||
        @to_objects ||= {}
 | 
			
		||||
        @to_objects[only] ||= downcased_unique_named.map do |name|
 | 
			
		||||
        @to_objects[only] ||= downcased_unique_named.flat_map do |name|
 | 
			
		||||
          load_formula_or_cask(name, only: only, method: method)
 | 
			
		||||
        rescue NoSuchKegError, FormulaUnavailableError, Cask::CaskUnavailableError
 | 
			
		||||
          ignore_unavailable ? [] : raise
 | 
			
		||||
        end.uniq.freeze
 | 
			
		||||
      end
 | 
			
		||||
      private :to_objects
 | 
			
		||||
@ -159,11 +168,17 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(only: T.nilable(Symbol)).returns([T::Array[Keg], T::Array[Cask::Cask]]) }
 | 
			
		||||
      def to_kegs_to_casks(only: nil)
 | 
			
		||||
        @to_kegs_to_casks ||= to_formulae_and_casks(only: only, method: :keg)
 | 
			
		||||
                              .partition { |o| o.is_a?(Keg) }
 | 
			
		||||
                              .map(&:freeze).freeze
 | 
			
		||||
      sig do
 | 
			
		||||
        params(only: T.nilable(Symbol), ignore_unavailable: T.nilable(T::Boolean), all_kegs: T.nilable(T::Boolean))
 | 
			
		||||
          .returns([T::Array[Keg], T::Array[Cask::Cask]])
 | 
			
		||||
      end
 | 
			
		||||
      def to_kegs_to_casks(only: nil, ignore_unavailable: nil, all_kegs: nil)
 | 
			
		||||
        method = all_kegs ? :kegs : :keg
 | 
			
		||||
        @to_kegs_to_casks ||= {}
 | 
			
		||||
        @to_kegs_to_casks[method] ||=
 | 
			
		||||
          to_formulae_and_casks(only: only, ignore_unavailable: ignore_unavailable, method: method)
 | 
			
		||||
          .partition { |o| o.is_a?(Keg) }
 | 
			
		||||
          .map(&:freeze).freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Array[String]) }
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# typed: true
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "keg"
 | 
			
		||||
@ -19,12 +19,13 @@ module Homebrew
 | 
			
		||||
  def uninstall_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      usage_banner <<~EOS
 | 
			
		||||
        `uninstall`, `rm`, `remove` [<options>] <formula>
 | 
			
		||||
        `uninstall`, `rm`, `remove` [<options>] <formula>|<cask>
 | 
			
		||||
 | 
			
		||||
        Uninstall <formula>.
 | 
			
		||||
        Uninstall a <formula> or <cask>.
 | 
			
		||||
      EOS
 | 
			
		||||
      switch "-f", "--force",
 | 
			
		||||
             description: "Delete all installed versions of <formula>."
 | 
			
		||||
             description: "Delete all installed versions of <formula>. Uninstall even if <cask> is not " \
 | 
			
		||||
                          "installed, overwrite existing files and ignore errors when removing files."
 | 
			
		||||
      switch "--ignore-dependencies",
 | 
			
		||||
             description: "Don't fail uninstall, even if <formula> is a dependency of any installed "\
 | 
			
		||||
                          "formulae."
 | 
			
		||||
@ -35,7 +36,7 @@ module Homebrew
 | 
			
		||||
             description: "Treat all named arguments as casks."
 | 
			
		||||
      conflicts "--formula", "--cask"
 | 
			
		||||
 | 
			
		||||
      min_named :formula
 | 
			
		||||
      min_named :formula_or_cask
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -45,35 +46,15 @@ module Homebrew
 | 
			
		||||
    only = :formula if args.formula? && !args.cask?
 | 
			
		||||
    only = :cask if args.cask? && !args.formula?
 | 
			
		||||
 | 
			
		||||
    if args.force?
 | 
			
		||||
      casks = []
 | 
			
		||||
      kegs_by_rack = {}
 | 
			
		||||
    all_kegs, casks = args.named.to_kegs_to_casks(only: only, ignore_unavailable: args.force?, all_kegs: args.force?)
 | 
			
		||||
    kegs_by_rack = all_kegs.group_by(&:rack)
 | 
			
		||||
 | 
			
		||||
      args.named.each do |name|
 | 
			
		||||
        if only != :cask
 | 
			
		||||
          rack = Formulary.to_rack(name)
 | 
			
		||||
          kegs_by_rack[rack] = rack.subdirs.map { |d| Keg.new(d) } if rack.directory?
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        next if only == :formula
 | 
			
		||||
 | 
			
		||||
        begin
 | 
			
		||||
          casks << Cask::CaskLoader.load(name)
 | 
			
		||||
        rescue Cask::CaskUnavailableError
 | 
			
		||||
          # Since the uninstall was forced, ignore any unavailable casks.
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      all_kegs, casks = args.named.to_kegs_to_casks(only: only)
 | 
			
		||||
      kegs_by_rack = all_kegs.group_by(&:rack)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    Uninstall.uninstall_kegs(kegs_by_rack,
 | 
			
		||||
                             force:               args.force?,
 | 
			
		||||
                             ignore_dependencies: args.ignore_dependencies?,
 | 
			
		||||
                             named_args:          args.named)
 | 
			
		||||
 | 
			
		||||
    return if casks.blank?
 | 
			
		||||
    Uninstall.uninstall_kegs(
 | 
			
		||||
      kegs_by_rack,
 | 
			
		||||
      force:               args.force?,
 | 
			
		||||
      ignore_dependencies: args.ignore_dependencies?,
 | 
			
		||||
      named_args:          args.named,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    Cask::Cmd::Uninstall.uninstall_casks(
 | 
			
		||||
      *casks,
 | 
			
		||||
@ -81,15 +62,5 @@ module Homebrew
 | 
			
		||||
      verbose:  args.verbose?,
 | 
			
		||||
      force:    args.force?,
 | 
			
		||||
    )
 | 
			
		||||
  rescue MultipleVersionsInstalledError => e
 | 
			
		||||
    ofail e
 | 
			
		||||
  ensure
 | 
			
		||||
    # If we delete Cellar/newname, then Cellar/oldname symlink
 | 
			
		||||
    # can become broken and we have to remove it.
 | 
			
		||||
    if HOMEBREW_CELLAR.directory?
 | 
			
		||||
      HOMEBREW_CELLAR.children.each do |rack|
 | 
			
		||||
        rack.unlink if rack.symlink? && !rack.resolved_path_exists?
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										64
									
								
								Library/Homebrew/cmd/zap.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Library/Homebrew/cmd/zap.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/cmd"
 | 
			
		||||
require "cask/cask_loader"
 | 
			
		||||
require "uninstall"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  extend T::Sig
 | 
			
		||||
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
  sig { returns(CLI::Parser) }
 | 
			
		||||
  def zap_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      usage_banner <<~EOS
 | 
			
		||||
        `zap` [<options>] <formula>|<cask>
 | 
			
		||||
 | 
			
		||||
        Remove all files associated with the given <formula> or <cask>.
 | 
			
		||||
        Implicitly also performs all actions associated with `uninstall`.
 | 
			
		||||
 | 
			
		||||
        *May remove files which are shared between applications.*
 | 
			
		||||
      EOS
 | 
			
		||||
      switch "-f", "--force",
 | 
			
		||||
             description: "Delete all installed versions of <formula>. Uninstall even if <cask> is not " \
 | 
			
		||||
                          "installed, overwrite existing files and ignore errors when removing files."
 | 
			
		||||
      switch "--ignore-dependencies",
 | 
			
		||||
             description: "Don't fail uninstall, even if <formula> is a dependency of any installed "\
 | 
			
		||||
                          "formulae."
 | 
			
		||||
 | 
			
		||||
      switch "--formula", "--formulae",
 | 
			
		||||
             description: "Treat all named arguments as formulae."
 | 
			
		||||
      switch "--cask", "--casks",
 | 
			
		||||
             description: "Treat all named arguments as casks."
 | 
			
		||||
      conflicts "--formula", "--cask"
 | 
			
		||||
 | 
			
		||||
      min_named :formula_or_cask
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def zap
 | 
			
		||||
    args = zap_args.parse
 | 
			
		||||
 | 
			
		||||
    only = :formula if args.formula? && !args.cask?
 | 
			
		||||
    only = :cask if args.cask? && !args.formula?
 | 
			
		||||
 | 
			
		||||
    all_kegs, casks = args.named.to_kegs_to_casks(only: only, ignore_unavailable: args.force?, all_kegs: args.force?)
 | 
			
		||||
    kegs_by_rack = all_kegs.group_by(&:rack)
 | 
			
		||||
 | 
			
		||||
    Uninstall.uninstall_kegs(
 | 
			
		||||
      kegs_by_rack,
 | 
			
		||||
      force:               args.force?,
 | 
			
		||||
      ignore_dependencies: args.ignore_dependencies?,
 | 
			
		||||
      named_args:          args.named,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    Cask::Cmd::Zap.zap_casks(
 | 
			
		||||
      *casks,
 | 
			
		||||
      binaries: EnvConfig.cask_opts_binaries?,
 | 
			
		||||
      verbose:  args.verbose?,
 | 
			
		||||
      force:    args.force?,
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -75,7 +75,7 @@ describe Cask::Cmd::Style, :cask do
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it "tries to find paths for all tokens" do
 | 
			
		||||
        expect(Cask::CaskLoader).to receive(:load).twice.and_return(double("cask", sourcefile_path: nil))
 | 
			
		||||
        expect(Cask::CaskLoader).to receive(:load).twice.and_return(instance_double(Cask::Cask, sourcefile_path: nil))
 | 
			
		||||
        subject
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -82,6 +82,16 @@ module Homebrew
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    rescue MultipleVersionsInstalledError => e
 | 
			
		||||
      ofail e
 | 
			
		||||
    ensure
 | 
			
		||||
      # If we delete Cellar/newname, then Cellar/oldname symlink
 | 
			
		||||
      # can become broken and we have to remove it.
 | 
			
		||||
      if HOMEBREW_CELLAR.directory?
 | 
			
		||||
        HOMEBREW_CELLAR.children.each do |rack|
 | 
			
		||||
          rack.unlink if rack.symlink? && !rack.resolved_path_exists?
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: false, named_args: [])
 | 
			
		||||
 | 
			
		||||
@ -104,3 +104,4 @@ upgrade
 | 
			
		||||
uses
 | 
			
		||||
vendor-gems
 | 
			
		||||
vendor-install
 | 
			
		||||
zap
 | 
			
		||||
 | 
			
		||||
@ -563,12 +563,12 @@ If no *`tap`* names are provided, display brief statistics for all installed tap
 | 
			
		||||
* `--json`:
 | 
			
		||||
  Print a JSON representation of *`tap`*. Currently the default and only accepted value for *`version`* is `v1`. See the docs for examples of using the JSON output: <https://docs.brew.sh/Querying-Brew>
 | 
			
		||||
 | 
			
		||||
### `uninstall`, `rm`, `remove` [*`options`*] *`formula`*
 | 
			
		||||
### `uninstall`, `rm`, `remove` [*`options`*] *`formula`*|*`cask`*
 | 
			
		||||
 | 
			
		||||
Uninstall *`formula`*.
 | 
			
		||||
Uninstall a *`formula`* or *`cask`*.
 | 
			
		||||
 | 
			
		||||
* `-f`, `--force`:
 | 
			
		||||
  Delete all installed versions of *`formula`*.
 | 
			
		||||
  Delete all installed versions of *`formula`*. Uninstall even if *`cask`* is not installed, overwrite existing files and ignore errors when removing files.
 | 
			
		||||
* `--ignore-dependencies`:
 | 
			
		||||
  Don't fail uninstall, even if *`formula`* is a dependency of any installed formulae.
 | 
			
		||||
* `--formula`:
 | 
			
		||||
@ -677,6 +677,22 @@ specify *`formula`* as a required or recommended dependency for their stable bui
 | 
			
		||||
* `--skip-recommended`:
 | 
			
		||||
  Skip all formulae that specify *`formula`* as `:recommended` type dependency.
 | 
			
		||||
 | 
			
		||||
### `zap` [*`options`*] *`formula`*|*`cask`*
 | 
			
		||||
 | 
			
		||||
Remove all files associated with the given *`formula`* or *`cask`*.
 | 
			
		||||
Implicitly also performs all actions associated with `uninstall`.
 | 
			
		||||
 | 
			
		||||
*May remove files which are shared between applications.*
 | 
			
		||||
 | 
			
		||||
* `-f`, `--force`:
 | 
			
		||||
  Delete all installed versions of *`formula`*. Uninstall even if *`cask`* is not installed, overwrite existing files and ignore errors when removing files.
 | 
			
		||||
* `--ignore-dependencies`:
 | 
			
		||||
  Don't fail uninstall, even if *`formula`* is a dependency of any installed formulae.
 | 
			
		||||
* `--formula`:
 | 
			
		||||
  Treat all named arguments as formulae.
 | 
			
		||||
* `--cask`:
 | 
			
		||||
  Treat all named arguments as casks.
 | 
			
		||||
 | 
			
		||||
### `--cache` [*`options`*] [*`formula`*|*`cask`*]
 | 
			
		||||
 | 
			
		||||
Display Homebrew's download cache. See also `HOMEBREW_CACHE`.
 | 
			
		||||
 | 
			
		||||
@ -782,12 +782,12 @@ Show information on each installed tap\.
 | 
			
		||||
\fB\-\-json\fR
 | 
			
		||||
Print a JSON representation of \fItap\fR\. Currently the default and only accepted value for \fIversion\fR is \fBv1\fR\. See the docs for examples of using the JSON output: \fIhttps://docs\.brew\.sh/Querying\-Brew\fR
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBuninstall\fR, \fBrm\fR, \fBremove\fR [\fIoptions\fR] \fIformula\fR"
 | 
			
		||||
Uninstall \fIformula\fR\.
 | 
			
		||||
.SS "\fBuninstall\fR, \fBrm\fR, \fBremove\fR [\fIoptions\fR] \fIformula\fR|\fIcask\fR"
 | 
			
		||||
Uninstall a \fIformula\fR or \fIcask\fR\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-f\fR, \fB\-\-force\fR
 | 
			
		||||
Delete all installed versions of \fIformula\fR\.
 | 
			
		||||
Delete all installed versions of \fIformula\fR\. Uninstall even if \fIcask\fR is not installed, overwrite existing files and ignore errors when removing files\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-ignore\-dependencies\fR
 | 
			
		||||
@ -940,6 +940,28 @@ Include all formulae that specify \fIformula\fR as \fB:optional\fR type dependen
 | 
			
		||||
\fB\-\-skip\-recommended\fR
 | 
			
		||||
Skip all formulae that specify \fIformula\fR as \fB:recommended\fR type dependency\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBzap\fR [\fIoptions\fR] \fIformula\fR|\fIcask\fR"
 | 
			
		||||
Remove all files associated with the given \fIformula\fR or \fIcask\fR\. Implicitly also performs all actions associated with \fBuninstall\fR\.
 | 
			
		||||
.
 | 
			
		||||
.P
 | 
			
		||||
\fIMay remove files which are shared between applications\.\fR
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-f\fR, \fB\-\-force\fR
 | 
			
		||||
Delete all installed versions of \fIformula\fR\. Uninstall even if \fIcask\fR is not installed, overwrite existing files and ignore errors when removing files\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-ignore\-dependencies\fR
 | 
			
		||||
Don\'t fail uninstall, even if \fIformula\fR is a dependency of any installed formulae\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-formula\fR
 | 
			
		||||
Treat all named arguments as formulae\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-cask\fR
 | 
			
		||||
Treat all named arguments as casks\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fB\-\-cache\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR]"
 | 
			
		||||
Display Homebrew\'s download cache\. See also \fBHOMEBREW_CACHE\fR\.
 | 
			
		||||
.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user