diff --git a/Library/Homebrew/cask/artifact/abstract_uninstall.rb b/Library/Homebrew/cask/artifact/abstract_uninstall.rb index e53bd28912..6c5f45982f 100644 --- a/Library/Homebrew/cask/artifact/abstract_uninstall.rb +++ b/Library/Homebrew/cask/artifact/abstract_uninstall.rb @@ -130,7 +130,12 @@ module Cask next if running_processes(bundle_id).empty? unless User.current.gui? - ohai "Not logged into a GUI; skipping quitting application ID '#{bundle_id}'." + opoo "Not logged into a GUI; skipping quitting application ID '#{bundle_id}'." + next + end + + unless User.automation_access? + opoo "Skipping quitting application ID '#{bundle_id}'. #{User.automation_access_instructions}" next end @@ -216,6 +221,11 @@ module Cask ["name", item] end + unless User.automation_access? + opoo "Skipping removal of login item #{id}. #{User.automation_access_instructions}" + next + end + ohai "Removing login item #{id}" system_command!( "osascript", 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 c8b2c50c09..f0e7c56fe1 100644 --- a/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb +++ b/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb @@ -116,16 +116,27 @@ shared_examples "#uninstall_phase or #zap_phase" do let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-quit")) } let(:bundle_id) { "my.fancy.package.app" } + it "is skipped when the user does not have automation access" do + allow(User).to receive(:automation_access?).and_return false + allow(User.current).to receive(:gui?).and_return true + allow(subject).to receive(:running_processes).with(bundle_id).and_return([[0, "", bundle_id]]) + + expect { + subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) + }.to output(/Skipping quitting application ID 'my.fancy.package.app'\./).to_stderr + end + it "is skipped when the user is not a GUI user" do allow(User.current).to receive(:gui?).and_return false allow(subject).to receive(:running_processes).with(bundle_id).and_return([[0, "", bundle_id]]) expect { subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) - }.to output(/Not logged into a GUI; skipping quitting application ID 'my.fancy.package.app'\./).to_stdout + }.to output(/Not logged into a GUI; skipping quitting application ID 'my.fancy.package.app'\./).to_stderr end it "quits a running application" do + allow(User).to receive(:automation_access?).and_return true allow(User.current).to receive(:gui?).and_return true expect(subject).to receive(:running_processes).with(bundle_id).ordered.and_return([[0, "", bundle_id]]) @@ -139,6 +150,7 @@ shared_examples "#uninstall_phase or #zap_phase" do end it "tries to quit the application for 10 seconds" do + allow(User).to receive(:automation_access?).and_return true allow(User.current).to receive(:gui?).and_return true allow(subject).to receive(:running_processes).with(bundle_id).and_return([[0, "", bundle_id]]) @@ -247,6 +259,8 @@ shared_examples "#uninstall_phase or #zap_phase" do let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-login-item")) } it "is supported" do + allow(User).to receive(:automation_access?).and_return true + expect(subject).to receive(:system_command!) .with( "osascript", diff --git a/Library/Homebrew/utils/user.rb b/Library/Homebrew/utils/user.rb index cf93d088d8..96f648d8c1 100644 --- a/Library/Homebrew/utils/user.rb +++ b/Library/Homebrew/utils/user.rb @@ -6,6 +6,23 @@ require "etc" require "system_command" class User < DelegateClass(String) + def self.automation_access? + return @automation_access if defined?(@automation_access) + + *_, status = system_command "osascript", args: [ + "-e", "with timeout of 0.5 seconds", + "-e", 'tell application "System Events" to get volume settings', + "-e", "end timeout" + ], print_stderr: false + + @automation_access = status.success? + end + + def self.automation_access_instructions + "Enable Automation Access for “Terminal > System Events” in " \ + "“System Preferences > Security > Privacy > Automation”." + end + def gui? out, _, status = system_command "who" return false unless status.success?