diff --git a/cmd/list-installed-launchjob-ids.rb b/cmd/list-installed-launchjob-ids.rb new file mode 100755 index 0000000000000..7089dc521cc5b --- /dev/null +++ b/cmd/list-installed-launchjob-ids.rb @@ -0,0 +1,63 @@ +# typed: strict +# frozen_string_literal: true + +require "abstract_command" +require "open3" + +module Homebrew + module Cmd + class ListInstalledLaunchjobIdsCmd < AbstractCommand + cmd_args do + description <<~EOS + List all installed launchjob IDs, which may be useful + in a Cask uninstall stanza, e.g.: + + uninstall launchctl: "job.id.goes.here" + + Launchctl jobs attributed to Apple will be omitted. + + If a launchctl job is currently loaded, and visible to the current + user, it will be followed by a plus symbol '(+)' in the output. + This can be verified via the command: + + /bin/launchctl list 'job.id.goes.here' + + See CONTRIBUTING.md and 'man launchctl' for more information. + EOS + + named_args :none + + hide_from_man_page! + end + + sig { override.returns(T.nilable(String)) } + def run + loaded = list_loaded_launchjob_ids + pattern = "{#{Dir.home},}/Library/Launch{Agents,Daemons}/**.plist" + puts Pathname + .glob(pattern) + .filter(&:readable?) + .filter_map { method(:read_label).call(it) } + .reject { it.start_with? "com.apple." } + .uniq.sort + .map { loaded.include?(it) ? "#{it} (+)" : it } + end + + sig { params(plist: Pathname).returns(T.nilable(String)) } + def read_label(plist) + xml = plist.read + if xml.start_with? "bplist" + xml, _, status = Open3.capture3("/usr/bin/plutil -convert xml1 -o - '#{plist}'") + return unless status.success? + end + Plist.parse_xml(xml, marshal: false)["Label"] + end + + sig { returns(T::Array[T.nilable(String)]) } + def list_loaded_launchjob_ids + loaded, = Open3.capture3("/bin/launchctl list") + loaded.lines.map { it.split(/\s+/).last } + end + end + end +end diff --git a/developer/bin/list_installed_launchjob_ids b/developer/bin/list_installed_launchjob_ids deleted file mode 100755 index 333e40a39d4e4..0000000000000 --- a/developer/bin/list_installed_launchjob_ids +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash -# -# list_installed_launchjob_ids -# - -### -### settings -### - -set -e # exit on any uncaught error -set +o histexpand # don't expand history expressions -shopt -s nocasematch # case-insensitive regular expressions - -### -### global variables -### - -# prefer GNU xargs -xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')" - -### -### functions -### - -launchjob_id_source_1 () { - /usr/bin/find ~/Library/LaunchAgents/ \ - ~/Library/LaunchDaemons/ \ - /Library/LaunchAgents/ \ - /Library/LaunchDaemons/ \ - -type f -print0 2>/dev/null | \ - "$xargs" -0 /usr/bin/perl -0777 -ne \ - 'while (m{\s*Label\s*\s*([^<]+?)}sg) { print "$1\n" }' -} - -merge_sources () { - /usr/bin/sort | /usr/bin/uniq -} - -clean_sources () { - /usr/bin/grep -E -v '^com\.apple\.' -} - -mark_up_sources () { - /usr/bin/perl -pe 's{\n}{\000}sg' | \ - "$xargs" -0 -I{} -n1 /bin/bash -c \ - 'printf "{}"; /bin/launchctl list "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"' -} - -### -### main -### - -_list_installed_launchjob_ids () { - - { - launchjob_id_source_1; - } | \ - merge_sources | \ - clean_sources | \ - mark_up_sources - -} - -# process args -if [[ $1 =~ ^-+h(elp)?$ ]]; then - printf "list_installed_launchjob_ids - -List all installed launchjob IDs, which may be useful -in a Cask uninstall stanza, e.g.: - - uninstall launchctl: 'job.id.goes.here' - -Launchctl jobs attributed to Apple will be omitted. - -If a launchctl job is currently loaded, and visible to the current -user, it will be followed by a plus symbol '(+)' in the output. -This can be verified via the command: - - /bin/launchctl list 'job.id.goes.here' - -See CONTRIBUTING.md and 'man launchctl' for more information. - -" - exit -fi - -# dispatch main -_list_installed_launchjob_ids "${@}" - -#