diff --git a/cmd/list-running-app-ids.rb b/cmd/list-running-app-ids.rb new file mode 100755 index 0000000000000..7e5a500f51a26 --- /dev/null +++ b/cmd/list-running-app-ids.rb @@ -0,0 +1,91 @@ +# typed: strict +# frozen_string_literal: true + +require "abstract_command" +require "open3" + +module Homebrew + module Cmd + class ListRunningAppIdsCmd < AbstractCommand + cmd_args do + usage_banner <<~EOS + `list-running-app-ids` [] + + Print a list of currently running Applications and associated + Bundle IDs, which may be useful in a Cask uninstall stanza, eg + + uninstall quit: 'bundle.id.goes.here' + + Applications attributed to Apple are excluded from the output. + + With optional , silently test if a given app + is running, setting a failing exit code if not. + + See CONTRIBUTING.md for more information. + EOS + + named_args :bundle_id, max: 1 + + hide_from_man_page! + end + + sig { override.void } + def run + app_names, bundle_ids = load_apps + test_bundle_id = args.named.first + + if test_bundle_id + Homebrew.failed = true unless bundle_ids.include?(test_bundle_id) + else + report_apps(app_names, bundle_ids) + end + end + + private + + sig { returns([T::Array[String], T::Array[String]]) } + def load_apps + out, err, status = + Open3.capture3("/usr/bin/osascript", "-e", + 'tell application "System Events" to get ' \ + "(name, bundle identifier, unix id) of every process") + odie(err) if status.exitstatus != 0 + + parts = out.split(", ") + one_third = parts.length / 3 + app_names = parts.shift(one_third) + bundle_ids = parts.shift(one_third) + [app_names, bundle_ids] + end + + sig { params(bundle_id: String).returns(T::Boolean) } + def excluded_bundle_id?(bundle_id) + bundle_id.start_with?("com.apple.") + end + + sig { params(app_name: String).returns(T::Boolean) } + def excluded_app_name?(app_name) + app_name == "osascript" + end + + sig { params(app_names: T::Array[String], bundle_ids: T::Array[String]).void } + def report_apps(app_names, bundle_ids) + col_width = Tty.width / 2 + running = Set.new + + app_names.zip(bundle_ids).each do |app_name, bundle_id| + next if bundle_id.nil? || app_name.nil? + next if excluded_bundle_id?(bundle_id) + next if excluded_app_name?(app_name) + + display_id = bundle_id.gsub(/^(missing value)$/, '<\1>') + running.add "#{display_id.ljust(col_width)}\t#{app_name}" + end + + puts "#{"bundle_id".ljust(col_width)}\tapp_name" + puts "-" * Tty.width + puts running.to_a.sort.join("\n") + end + end + end +end diff --git a/developer/bin/list_ids_in_app b/developer/bin/list_ids_in_app index f088cc918cacb..36ae6b886d90a 100755 --- a/developer/bin/list_ids_in_app +++ b/developer/bin/list_ids_in_app @@ -109,7 +109,7 @@ clean_sources () { mark_up_sources () { /usr/bin/perl -pe 's{\n}{\000}sg' | \ "$xargs" -0 -I{} -n1 /bin/bash -c \ - "printf '{}'; $scriptdir/list_running_app_ids -t '{}' >/dev/null 2>&1 && printf ' (+)'; printf "\\\\n"" + "printf '{}'; brew list-running-app-ids '{}' >/dev/null 2>&1 && printf ' (+)'; printf "\\\\n"" } ### @@ -151,7 +151,7 @@ are excluded from the output. If a given app is currently running, it will be followed by a plus symbol '(+)' in the output. This can be verified via the command - list_running_app_ids | grep 'app.id.goes.here' + brew list-running-app-ids | grep 'app.id.goes.here' See CONTRIBUTING.md for more information. diff --git a/developer/bin/list_running_app_ids b/developer/bin/list_running_app_ids deleted file mode 100755 index cdc64eec59bb3..0000000000000 --- a/developer/bin/list_running_app_ids +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# Standalone scripts are fine to use global variables -# rubocop:disable Style/GlobalVars - -# -# list_running_app_ids -# - -### -### dependencies -### - -require "open3" -require "io/console" - -### -### globals -### - -$opt_test = nil -$COLUMNS = IO.console.winsize.last - -### -### methods -### - -def check_ruby - return if RUBY_VERSION.to_f >= 2.0 - - print "You are currently using Ruby ", RUBY_VERSION, ", but version 2.0 or above is required." - exit 1 -end - -def usage - <<~EOS - list_running_app_ids [ -t ] - - Print a list of currently running Applications and associated - Bundle IDs, which may be useful in a Cask uninstall stanza, eg - - uninstall quit: 'bundle.id.goes.here' - - Applications attributed to Apple are excluded from the output. - - With optional "-t ", silently test if a given app - is running, exiting with an error code if not. - - See CONTRIBUTING.md for more information. - - EOS -end - -def process_args - until ARGV.empty? - if ARGV.first =~ /^-+t(?:est)?$/ && ARGV.length > 1 - ARGV.shift - $opt_test = ARGV.shift - elsif /^-+h(?:elp)?$/.match?(ARGV.first) - puts usage - exit 0 - else - puts usage - exit 1 - end - end -end - -def load_apps - out, err, status = - Open3.capture3("/usr/bin/osascript", "-e", - 'tell application "System Events" to get (name, bundle identifier, unix id) of every process') - if status.exitstatus.positive? - puts err - exit status.exitstatus - end - out = out.split(", ") - one_third = out.length / 3 - @app_names = out.shift(one_third) - @bundle_ids = out.shift(one_third) - @unix_ids = out.shift(one_third) -end - -def test_app(bundle) - @bundle_ids.include?(bundle) ? 0 : 1 -end - -def excluded_bundle_id(bundle_id) - /^com\.apple\./.match(bundle_id) -end - -def excluded_app_name(app_name) - /^osascript$/.match(app_name) # this script itself -end - -def report_apps - running = Set.new - @app_names.zip(@bundle_ids, @unix_ids).each do |app_name, bundle_id, _unix_id| - next if excluded_bundle_id bundle_id - next if excluded_app_name app_name - - bundle_id.gsub!(/^(missing value)$/, '<\1>') - running.add "#{bundle_id.ljust($COLUMNS / 2)}\t#{app_name}" - end - - puts "#{"bundle_id".ljust($COLUMNS / 2)}\tapp_name" - puts "-" * $COLUMNS - puts running.to_a.sort.join "\n" -end - -### -### main -### - -check_ruby -process_args -load_apps - -if $opt_test - exit test_app($opt_test) -else - report_apps -end -# rubocop:enable Style/GlobalVars