diff --git a/Library/Homebrew/cask/artifact/uninstall.rb b/Library/Homebrew/cask/artifact/uninstall.rb index a91efd2fa8..4b83e18325 100644 --- a/Library/Homebrew/cask/artifact/uninstall.rb +++ b/Library/Homebrew/cask/artifact/uninstall.rb @@ -3,17 +3,26 @@ require "cask/artifact/abstract_uninstall" +UPGRADE_REINSTALL_SKIP_DIRECTIVES = [:quit, :signal].freeze + module Cask module Artifact # Artifact corresponding to the `uninstall` stanza. # # @api private class Uninstall < AbstractUninstall - def uninstall_phase(**options) - ORDERED_DIRECTIVES.reject { |directive_sym| directive_sym == :rmdir } - .each do |directive_sym| - dispatch_uninstall_directive(directive_sym, **options) - end + def uninstall_phase(upgrade: false, reinstall: false, **options) + filtered_directives = ORDERED_DIRECTIVES.filter do |directive_sym| + next false if directive_sym == :rmdir + + next false if (upgrade || reinstall) && UPGRADE_REINSTALL_SKIP_DIRECTIVES.include?(directive_sym) + + true + end + + filtered_directives.each do |directive_sym| + dispatch_uninstall_directive(directive_sym, **options) + end end def post_uninstall_phase(**options) diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index 0cacc005fd..cb9d11930f 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -472,6 +472,8 @@ on_request: true) skip: clear, force: force?, successor: successor, + upgrade: upgrade?, + reinstall: reinstall?, ) end diff --git a/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb b/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb index ec195718f0..872a154ae5 100644 --- a/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb +++ b/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb @@ -228,6 +228,20 @@ shared_examples "#uninstall_phase or #zap_phase" do end.to output(/Application 'my.fancy.package.app' quit successfully\./).to_stdout end + it "does not attempt to quit when upgrading or reinstalling" do + next if artifact_dsl_key == :zap + + allow(User.current).to receive(:gui?).and_return true + + expect(subject).not_to receive(:running?) + expect(subject).not_to receive(:quit) + + expect do + subject.public_send(:"#{artifact_dsl_key}_phase", upgrade: true, command: fake_system_command) + subject.public_send(:"#{artifact_dsl_key}_phase", reinstall: true, command: fake_system_command) + end + end + it "tries to quit the application for 10 seconds" do allow(User.current).to receive(:gui?).and_return true @@ -261,6 +275,20 @@ shared_examples "#uninstall_phase or #zap_phase" do subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) end + + it "does not send signal when upgrading or reinstalling" do + next if artifact_dsl_key == :zap + + allow(subject).to receive(:running_processes).with(bundle_id) + .and_return(unix_pids.map { |pid| [pid, 0, bundle_id] }) + + signals.each do |_signal| + expect(Process).not_to receive(:kill) + end + + subject.public_send(:"#{artifact_dsl_key}_phase", upgrade: true, command: fake_system_command) + subject.public_send(:"#{artifact_dsl_key}_phase", reinstall: true, command: fake_system_command) + end end [:delete, :trash].each do |directive| diff --git a/docs/Cask-Cookbook.md b/docs/Cask-Cookbook.md index 49aee219b9..6b9d230528 100644 --- a/docs/Cask-Cookbook.md +++ b/docs/Cask-Cookbook.md @@ -761,8 +761,8 @@ Since `pkg` installers can do arbitrary things, different techniques are needed * **`early_script:`** (string or hash) - like [`script:`](#uninstall-script), but runs early (for special cases, best avoided) * [`launchctl:`](#uninstall-launchctl) (string or array) - IDs of `launchd` jobs to remove -* [`quit:`](#uninstall-quit) (string or array) - bundle IDs of running applications to quit -* [`signal:`](#uninstall-signal) (array of arrays) - signal numbers and bundle IDs of running applications to send a Unix signal to (for when `quit:` does not work) +* [`quit:`](#uninstall-quit) (string or array) - bundle IDs of running applications to quit (does not run when uninstall is initiated by `brew upgrade` or `brew reinstall`) +* [`signal:`](#uninstall-signal) (array of arrays) - signal numbers and bundle IDs of running applications to send a Unix signal to - for when `quit:` does not work (does not run when uninstall is initiated by `brew upgrade` or `brew reinstall`) * [`login_item:`](#uninstall-login_item) (string or array) - names of login items to remove * [`kext:`](#uninstall-kext) (string or array) - bundle IDs of kexts to unload from the system * [`script:`](#uninstall-script) (string or hash) - relative path to an uninstall script to be run via sudo; use hash if args are needed