mirror of
https://github.com/wavetermdev/homebrew-cask.git
synced 2026-08-05 13:43:24 -07:00
Move back documentation and developer scripts. (#23920)
This commit is contained in:
Executable
+190
@@ -0,0 +1,190 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o pipefail
|
||||
|
||||
readonly program="$(basename "$0")"
|
||||
skip_curl_verify=0
|
||||
verbose=0
|
||||
|
||||
syntax_error() {
|
||||
echo "$program: $1" >&2
|
||||
echo "Try \`$program --help\` for more information." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
depends_on() {
|
||||
formula="$1"
|
||||
[[ "$#" -eq 2 ]] && cmd="$2" || cmd=$(basename "${formula}")
|
||||
|
||||
if [[ ! $(which ${cmd}) ]]; then
|
||||
echo -e "$(tput setaf 1)
|
||||
This script depends on '${cmd}'.
|
||||
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ${formula}'.
|
||||
$(tput sgr0)" | sed -E 's/ {6}//' >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
depends_on 'tsparber/tiny-scripts/curl-check-url'
|
||||
|
||||
usage() {
|
||||
echo "
|
||||
This script changes the url, appcast and homepage stanzas to https
|
||||
|
||||
After changing to https a HTTP GET request is performed to verify if the url is reachable.
|
||||
If the https url is not reachable it is reverted to the previous version.
|
||||
|
||||
Known Issues: If multiple url/appcast stanzas are present, all urls are changed but only
|
||||
those for the current os are verified.
|
||||
|
||||
If no cask name is given the current work directory is scanned with the given options.
|
||||
|
||||
usage: $program [options] [<cask_name>]
|
||||
options:
|
||||
-s, --skip-verify Skip checking for a HTTP 200 Status Code using curl.
|
||||
--verbose Show more verbose output.
|
||||
-h, --help Show this help.
|
||||
|
||||
Based on: https://github.com/vitorgalvao/tiny-scripts/blob/master/cask-repair
|
||||
" | sed -E 's/^ {4}//'
|
||||
}
|
||||
|
||||
# available flags
|
||||
while [[ "$1" ]]; do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-s | --skip-verify)
|
||||
skip_curl_verify=1
|
||||
;;
|
||||
--verbose)
|
||||
verbose=1
|
||||
;;
|
||||
-*)
|
||||
syntax_error "unrecognized option: $1"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# define function to check if given URL exists and is reachable using HTTPS
|
||||
check_url_for_https() {
|
||||
cask_url="$1"
|
||||
verbose_option=""
|
||||
|
||||
[[ ${verbose} -ne 0 ]] && verbose_option="-v "
|
||||
|
||||
# check if the URL sends a 200 HTTP code, else abort
|
||||
curl-check-url ${verbose_option} "${cask_url}" > /dev/null
|
||||
exit_code=$?
|
||||
|
||||
if [[ exit_code -ne 0 ]]; then
|
||||
echo "curl returned ${exit_code}: FAIL for ${cask_url}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# define function to modify part of stanza
|
||||
replace_protocol_of_stanza() {
|
||||
cask_file="$1"
|
||||
stanza="$2"
|
||||
old_value="$3"
|
||||
new_value="$4"
|
||||
|
||||
sed "s|${stanza} \(['\"]\)${old_value}://|${stanza} \1${new_value}://|g" "${cask_file}" > tmpfile
|
||||
mv tmpfile "${cask_file}"
|
||||
}
|
||||
|
||||
# define abort function, that will reset the state
|
||||
finish() {
|
||||
# show message
|
||||
if [[ "$1" == 'abort' ]]; then
|
||||
echo -e "$(tput setaf 1)$2$(tput sgr0)\n"
|
||||
[[ ! -z "${cask_file}" ]] && git checkout -- "${cask_file}"
|
||||
exit 1
|
||||
elif [[ "$1" == 'success' ]]; then
|
||||
echo -e "$(tput setaf 2)Updated: ${cask_name} is now using HTTPS$(tput sgr0)\n"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# cleanup if aborted with ⌃C
|
||||
trap 'finish abort "You aborted"' SIGINT
|
||||
|
||||
# exit if not inside a 'homebrew-*/Casks' directory
|
||||
casks_dir=$(pwd | perl -ne 'print m{homebrew-[^/]+/Casks}')
|
||||
if [[ -z "${casks_dir}" ]]; then
|
||||
echo -e "\n$(tput setaf 1)You need to be inside a '/homebrew-*/Casks' directory$(tput sgr0)\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# exit if no argument was given: Run in current directory
|
||||
if [[ -z "$1" ]]; then
|
||||
options=""
|
||||
[[ ${skip_curl_verify} -ne 0 ]] && options+=" --skip-verify"
|
||||
[[ ${verbose} -ne 0 ]] && options+=" --verbose"
|
||||
|
||||
for file in *.rb;
|
||||
do
|
||||
"$0" ${options} ${file}
|
||||
done
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# clean the cask's name, and check if it is valid
|
||||
cask_name="$1"
|
||||
[[ "${cask_name}" == *'.rb' ]] && cask_name=$(echo "${cask_name}" | sed 's|\.rb$||')
|
||||
cask_file="./${cask_name}.rb"
|
||||
[[ ! -f "${cask_file}" ]] && finish abort 'There is no such cask'
|
||||
|
||||
# initial tasks
|
||||
git checkout -- "${cask_file}"
|
||||
|
||||
# check if a http url exists
|
||||
cask_contains_http=$(grep "['\"]http://" "${cask_file}")
|
||||
if [[ -z ${cask_contains_http} ]]; then
|
||||
echo -e "Skipped ${cask_name} no http found\n"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
updated_stanzas=0
|
||||
for stanza in url appcast homepage; do
|
||||
# Check if the stanza exists
|
||||
stanza_contained=$(grep "${stanza} ['\"]" "${cask_file}")
|
||||
[[ -z ${stanza_contained} ]] && continue
|
||||
|
||||
stanza_contains_https=$(grep "${stanza} ['\"]http://" "${cask_file}")
|
||||
if [[ -z ${stanza_contains_https} ]]; then
|
||||
# echo "Skipped stanza ${stanza} in ${cask_name} no http url found"
|
||||
continue
|
||||
fi
|
||||
|
||||
replace_protocol_of_stanza ${cask_file} ${stanza} "http" "https"
|
||||
|
||||
if [[ ${skip_curl_verify} -eq 0 ]]; then
|
||||
check_url_for_https $(brew cask _stanza ${stanza} "${cask_name}")
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Restored original value for stanza ${stanza} as curl check failed"
|
||||
replace_protocol_of_stanza ${cask_file} ${stanza} "https" "http"
|
||||
else
|
||||
updated_stanzas=$((updated_stanzas+1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${updated_stanzas} -ne 0 ]]; then
|
||||
finish success
|
||||
else
|
||||
finish abort "no updated stanzas after verify for ${cask_name}"
|
||||
fi
|
||||
Executable
+199
@@ -0,0 +1,199 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# develop_brew_cask
|
||||
#
|
||||
# Called via symlink as:
|
||||
# production_brew_cask
|
||||
#
|
||||
|
||||
called_as="$(basename "$0")"
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e # exit on any uncaught error
|
||||
set +o histexpand # don't expand history expressions
|
||||
shopt -s nocasematch # case-insensitive regular expressions
|
||||
|
||||
###
|
||||
### configurable global variables
|
||||
###
|
||||
|
||||
taps_subdir="Library/Taps"
|
||||
cask_tap_subdir="caskroom/homebrew-cask"
|
||||
dev_links=("cmd" "lib" "Casks")
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
warn () {
|
||||
local message="$*"
|
||||
message="${message//\\t/$'\011'}"
|
||||
message="${message//\\n/$'\012'}"
|
||||
message="${message%${message##*[![:space:]]}}"
|
||||
printf "%s\n" "$message" 1>&2
|
||||
}
|
||||
|
||||
die () {
|
||||
warn "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd_to_project_root () {
|
||||
local script_dir git_root
|
||||
script_dir="$(/usr/bin/dirname "$0")"
|
||||
cd "$script_dir"
|
||||
git_root="$(git rev-parse --show-toplevel)"
|
||||
if [[ -z "$git_root" ]]; then
|
||||
die "ERROR: Could not find git project root"
|
||||
fi
|
||||
cd "$git_root"
|
||||
}
|
||||
|
||||
cd_to_tap_dir () {
|
||||
local taps_dir="$1"
|
||||
local tap_dir="$2"
|
||||
if [[ ! -d "$tap_dir" ]]; then
|
||||
die "ERROR: Could not find tap dir under $taps_dir/"
|
||||
fi
|
||||
cd "$tap_dir"
|
||||
}
|
||||
|
||||
not_inside_homebrew () {
|
||||
local tap_dir="$1"
|
||||
local git_root="$2"
|
||||
if [[ "$(/usr/bin/stat -L -f '%i' -- "$tap_dir")" -eq "$(/usr/bin/stat -L -f '%i' -- "$git_root")" ]]; then
|
||||
die "\nERROR: Run this script in your private repo, not inside Homebrew.\n"
|
||||
fi
|
||||
}
|
||||
|
||||
remove_dev_links () {
|
||||
for link_name in "${dev_links[@]}"; do
|
||||
remove_dev_link "$link_name"
|
||||
done
|
||||
printf "brew-cask is now in production mode\n"
|
||||
printf "It is safe to run 'brew update' if you are in production mode for all Caskroom repos.\n"
|
||||
}
|
||||
|
||||
create_dev_links () {
|
||||
local git_root="$1"
|
||||
for link_name in "${dev_links[@]}"; do
|
||||
create_dev_link "$git_root" "$link_name"
|
||||
done
|
||||
printf "brew-cask is now in development mode\n"
|
||||
printf "Note: it is not safe to run 'brew update' while in development mode\n"
|
||||
}
|
||||
|
||||
remove_dev_link () {
|
||||
local link_name="$1"
|
||||
/bin/rm -- "$link_name"
|
||||
/bin/mv -- "production_$link_name" "$link_name"
|
||||
}
|
||||
|
||||
create_dev_link () {
|
||||
local git_root="$1"
|
||||
local link_name="$2"
|
||||
/bin/mv -- "$link_name" "production_$link_name"
|
||||
/bin/ln -s -- "$git_root/$link_name" .
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_develop_brew_cask_develop_action () {
|
||||
die "brew-cask is already set up for development"
|
||||
}
|
||||
|
||||
_develop_brew_cask_production_action () {
|
||||
create_dev_links "$git_root"
|
||||
}
|
||||
|
||||
_production_brew_cask_develop_action () {
|
||||
remove_dev_links
|
||||
}
|
||||
|
||||
_production_brew_cask_production_action () {
|
||||
die "brew-cask is already set up for production"
|
||||
}
|
||||
|
||||
_main () {
|
||||
local git_root brew_repository taps_dir tap_dir
|
||||
|
||||
# initialization
|
||||
cd_to_project_root
|
||||
git_root="$(/bin/pwd)"
|
||||
brew_repository="$(brew --repository)"
|
||||
taps_dir="$brew_repository/$taps_subdir"
|
||||
tap_dir="$taps_dir/$cask_tap_subdir"
|
||||
|
||||
# sanity check
|
||||
not_inside_homebrew "$tap_dir" "$git_root"
|
||||
|
||||
# action
|
||||
cd_to_tap_dir "$taps_dir" "$tap_dir"
|
||||
if [[ -e "production_lib" ]]; then
|
||||
eval "_${called_as}_develop_action"
|
||||
else
|
||||
eval "_${called_as}_production_action"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
_develop_brew_cask_usage () {
|
||||
|
||||
printf "develop_brew_cask
|
||||
|
||||
Symlink private repo directories into Homebrew's Cellar, so
|
||||
that the 'brew cask' command will use code and Casks from
|
||||
the current development branch in your private repo.
|
||||
|
||||
Saves the production Homebrew directories under new names.
|
||||
|
||||
You can reverse this operation with 'production_brew_cask'.
|
||||
|
||||
Note: it is not safe to run 'brew update' while development
|
||||
mode is in effect.
|
||||
|
||||
"
|
||||
|
||||
}
|
||||
|
||||
_production_brew_cask_usage () {
|
||||
|
||||
printf "production_brew_cask
|
||||
|
||||
Undo all symlinks created by 'develop_brew_cask' so that the
|
||||
'brew cask' command will use only released code and Casks
|
||||
within Homebrew.
|
||||
|
||||
After running this command it is safe to run 'brew update',
|
||||
unless you are using similar scripts to create symlinks into
|
||||
other Caskroom development repos.
|
||||
|
||||
"
|
||||
|
||||
}
|
||||
|
||||
# ensure we're called by a valid name
|
||||
case "${called_as}" in
|
||||
develop_brew_cask) ;;
|
||||
production_brew_cask) ;;
|
||||
*)
|
||||
die "ERROR: name ${called_as} not recognized"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ ]]; then
|
||||
eval "_${called_as}_usage"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_main "${@}"
|
||||
|
||||
#
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
|
||||
readonly caskroom_online='https://github.com/caskroom'
|
||||
readonly caskroom_repos_dir='/tmp/caskroom_repos'
|
||||
readonly caskroom_repos=(homebrew-cask homebrew-versions homebrew-fonts homebrew-eid)
|
||||
readonly curl_flags=(--silent --location --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36')
|
||||
inaccessible_appcasts=()
|
||||
|
||||
if [[ ! $(which 'ghi') ]] || ! security find-internet-password -s github.com -l 'ghi token' &> /dev/null; then
|
||||
echo -e "$(tput setaf 1)
|
||||
This script requires 'ghi' installed and configured.
|
||||
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ghi'.
|
||||
To configure it, run 'ghi config --auth <username>'. Your Github password will be required, but is never stored.
|
||||
$(tput sgr0)" | sed -E 's/ {4}//' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function message {
|
||||
echo "${1}"
|
||||
}
|
||||
|
||||
function go_to_repos_dir {
|
||||
[[ ! -d "${caskroom_repos_dir}" ]] && mkdir -p "${caskroom_repos_dir}"
|
||||
cd "${caskroom_repos_dir}" || exit 1
|
||||
}
|
||||
|
||||
function go_to_repo_and_update {
|
||||
local repo_name repo_dir casks_dir
|
||||
|
||||
repo_name="${1}"
|
||||
repo_dir="${caskroom_repos_dir}/${repo_name}"
|
||||
casks_dir="${repo_dir}/Casks"
|
||||
|
||||
if [[ ! -d "${repo_dir}" ]]; then
|
||||
go_to_repos_dir
|
||||
|
||||
message "Cloning ${repo_name}…"
|
||||
git clone "https://github.com/caskroom/${repo_name}.git" --quiet
|
||||
|
||||
cd "${casks_dir}" || exit 1
|
||||
else
|
||||
cd "${casks_dir}" || exit 1
|
||||
|
||||
message "Updating ${repo_name}…"
|
||||
git pull --rebase origin master --quiet
|
||||
fi
|
||||
}
|
||||
|
||||
function open_issue {
|
||||
local repo_name cask_name cask_url version appcast_url issue_number
|
||||
|
||||
repo_name="${1}"
|
||||
cask_name="${2}"
|
||||
cask_url="${caskroom_online}/${repo_name}/blob/master/Casks/${cask_name}.rb"
|
||||
version="${3}"
|
||||
appcast_url="${4}"
|
||||
|
||||
message="$(echo "Outdated cask: ${cask_name}
|
||||
|
||||
Outdated cask: [\`${cask_name}\`](${cask_url}).
|
||||
|
||||
Info:
|
||||
+ version: \`${version}\`.
|
||||
+ appcast url: ${appcast_url}.
|
||||
" | sed -E 's/^ {4}//')"
|
||||
|
||||
issue_number=$(ghi open --label 'outdated appcast' --message "${message}" | head -1 | perl -pe 's/^#(\d+): .*/\1/')
|
||||
message "Opened issue: https://github.com/caskroom/${repo_name}/issues/${issue_number}."
|
||||
}
|
||||
|
||||
function is_appcast_available {
|
||||
local appcast_url
|
||||
|
||||
appcast_url="${1}"
|
||||
|
||||
http_status="$(curl "${curl_flags[@]}" --head --write-out '%{http_code}' "${appcast_url}" -o '/dev/null')"
|
||||
|
||||
[[ "${http_status}" == 200 ]]
|
||||
}
|
||||
|
||||
function report_outdated_appcasts {
|
||||
local repo_name cask_name appcast_url current_checkpoint new_checkpoint version
|
||||
|
||||
repo_name="${1}"
|
||||
|
||||
for cask_file in ./*; do
|
||||
appcast_url="$(brew cask _stanza appcast "${cask_file}")"
|
||||
[[ -z "${appcast_url}" ]] && continue # skip early if there is no appcast
|
||||
|
||||
cask_name="$(basename "${cask_file%.*}")"
|
||||
|
||||
message "Verifying appcast checkpoint for ${cask_name}…"
|
||||
|
||||
if is_appcast_available "${appcast_url}"; then
|
||||
current_checkpoint="$(brew cask _stanza --yaml appcast "${cask_file}" | grep '^- :checkpoint' | awk '{print $3}')"
|
||||
new_checkpoint="$(curl "${curl_flags[@]}" --compressed "${appcast_url}" | sed 's|<pubDate>[^<]*</pubDate>||g' | shasum --algorithm 256 | awk '{ print $1 }')"
|
||||
else
|
||||
message "There was an error checking the appcast for ${cask_name}."
|
||||
inaccessible_appcasts+=("${repo_name}/${cask_name}")
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "${current_checkpoint}" != "${new_checkpoint}" ]]; then
|
||||
version="$(brew cask _stanza version "${cask_file}")"
|
||||
|
||||
message "${cask_name} is outdated. Opening issue in ${repo_name}…"
|
||||
open_issue "${repo_name}" "${cask_name}" "${version}" "${appcast_url}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
for repo in "${caskroom_repos[@]}"; do
|
||||
go_to_repo_and_update "${repo}"
|
||||
report_outdated_appcasts "${repo}"
|
||||
done
|
||||
|
||||
if [[ ${#inaccessible_appcasts[@]} -gt 0 ]];then
|
||||
echo # empty line
|
||||
message 'Some casks have appcasts that errored out, and may need to be rechecked:'
|
||||
printf '%s\n' "${inaccessible_appcasts[@]}"
|
||||
fi
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
|
||||
readonly user_agent=(--user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36')
|
||||
|
||||
usage() {
|
||||
local program exit_status
|
||||
|
||||
program="$(basename "$0")"
|
||||
exit_status="$1"
|
||||
|
||||
echo "usage: ${program} <path_to_app>"
|
||||
exit "${exit_status}"
|
||||
}
|
||||
|
||||
absolute_path() {
|
||||
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
||||
}
|
||||
|
||||
appcast_found_error() {
|
||||
local error_reason="$1"
|
||||
|
||||
echo "An appcast was found pointing to ${appcast_url}, but it ${error_reason}. You should:
|
||||
|
||||
1. Check your internet connection.
|
||||
2. Try again later.
|
||||
3. Contact the developer."
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
# exit if no argument (or more than one) was given
|
||||
if [[ -z "$1" ]] || [[ -n "$2" ]]; then
|
||||
usage 1
|
||||
fi
|
||||
|
||||
# get plist
|
||||
path_to_app="$(absolute_path "$1")"
|
||||
path_to_plist="${path_to_app}/Contents/Info.plist"
|
||||
|
||||
if [[ ! -f "${path_to_plist}" ]]; then
|
||||
echo 'You need to use this on a .app bundle. Please verify your target.'
|
||||
usage 1
|
||||
fi
|
||||
|
||||
# get appcast
|
||||
appcast_url="$(defaults read "${path_to_plist}" 'SUFeedURL' 2>/dev/null)"
|
||||
|
||||
if [[ -z "${appcast_url}" ]]; then
|
||||
echo 'It appears this app does not have a Sparkle appcast'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# validate appcast
|
||||
appcast_http_response="$(curl --silent --head "${user_agent[@]}" --write-out '%{http_code}' "${appcast_url}" -o /dev/null)"
|
||||
[[ "${appcast_http_response}" != '200' ]] && appcast_found_error "returned a non-200 (OK) HTTP response code (${appcast_http_response})"
|
||||
|
||||
appcast_checkpoint=$(curl --silent --compressed --location "${user_agent[@]}" "${appcast_url}" | sed 's|<pubDate>[^<]*</pubDate>||g' | shasum --algorithm 256 | awk '{ print $1 }')
|
||||
[[ "${appcast_checkpoint}" == 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' ]] && appcast_found_error 'seems to be empty'
|
||||
|
||||
# output appcast
|
||||
echo "A Sparkle appcast was found. You should add it to your cask as
|
||||
|
||||
appcast '${appcast_url}',
|
||||
checkpoint: '${appcast_checkpoint}'
|
||||
|
||||
You should likely also add 'auto_updates true'"
|
||||
|
||||
exit 0
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
|
||||
IFS=$'\n'
|
||||
|
||||
readonly caskroom_repos_dir='/tmp/caskroom_repos'
|
||||
readonly caskroom_repos=(homebrew-cask homebrew-versions homebrew-fonts homebrew-eid)
|
||||
|
||||
if [[ ! $(which 'ghi') ]] || ! security find-internet-password -s github.com -l 'ghi token' &> /dev/null; then
|
||||
echo -e "$(tput setaf 1)
|
||||
This script requires 'ghi' installed and configured.
|
||||
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ghi'.
|
||||
To configure it, run 'ghi config --auth <username>'. Your Github password will be required, but is never stored.
|
||||
$(tput sgr0)" | sed -E 's/ {4}//' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! $(which 'cask-repair') ]]; then
|
||||
echo -e "$(tput setaf 1)
|
||||
This script requires 'cask-repair'.
|
||||
If you have [Homebrew](http://brew.sh), you can install it with 'brew install vitorgalvao/tiny-scripts/cask-repair'.
|
||||
$(tput sgr0)" | sed -E 's/ {4}//' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function message {
|
||||
echo "${1}"
|
||||
}
|
||||
|
||||
function go_to_repos_dir {
|
||||
[[ ! -d "${caskroom_repos_dir}" ]] && mkdir -p "${caskroom_repos_dir}"
|
||||
cd "${caskroom_repos_dir}" || exit 1
|
||||
}
|
||||
|
||||
function go_to_repo_and_update {
|
||||
local repo_name repo_dir casks_dir
|
||||
|
||||
repo_name="${1}"
|
||||
repo_dir="${caskroom_repos_dir}/${repo_name}"
|
||||
casks_dir="${repo_dir}/Casks"
|
||||
|
||||
if [[ ! -d "${repo_dir}" ]]; then
|
||||
go_to_repos_dir
|
||||
|
||||
message "Cloning ${repo_name}…"
|
||||
git clone "https://github.com/caskroom/${repo_name}.git" --quiet
|
||||
|
||||
cd "${casks_dir}" || exit 1
|
||||
else
|
||||
cd "${casks_dir}" || exit 1
|
||||
|
||||
message "Updating ${repo_name}…"
|
||||
git pull --rebase origin master --quiet
|
||||
fi
|
||||
}
|
||||
|
||||
function fix_outdated_appcasts {
|
||||
local issue_number cask_name pr_number
|
||||
|
||||
for line in $(ghi list --state open --no-pulls --label 'outdated appcast' --reverse | tail +2); do
|
||||
[[ "${line}" == 'None.' ]] && break # exit early if there are no relevant issues in repo
|
||||
|
||||
issue_number="$(awk '{print $1}' <<< "${line}")"
|
||||
cask_name="$(awk '{print $4}' <<< "${line}")"
|
||||
|
||||
cask-repair --pull origin --push origin --open-appcast --closes-issue "${issue_number}" --blind-submit "${cask_name}"
|
||||
|
||||
if [[ "$?" -eq 0 ]]; then
|
||||
pr_number="$(ghi list --pulls --creator | sed -n 2p | awk '{print $1}')"
|
||||
ghi edit --label 'outdated appcast' "${pr_number}" &>/dev/null
|
||||
ghi comment --close --message "Closing in favour of #${pr_number}." "${issue_number}" &>/dev/null
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
for repo in "${caskroom_repos[@]}"; do
|
||||
go_to_repo_and_update "${repo}"
|
||||
fix_outdated_appcasts
|
||||
done
|
||||
Executable
+418
@@ -0,0 +1,418 @@
|
||||
#!/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby
|
||||
#
|
||||
# generate_cask_token
|
||||
#
|
||||
# todo:
|
||||
#
|
||||
# remove Ruby 2.0 dependency and change shebang line
|
||||
#
|
||||
# detect Cask files which differ only by the placement of hyphens.
|
||||
#
|
||||
# merge entirely into "brew cask create" command
|
||||
#
|
||||
|
||||
###
|
||||
### dependencies
|
||||
###
|
||||
|
||||
require "pathname"
|
||||
require "open3"
|
||||
|
||||
begin
|
||||
# not available by default
|
||||
require "active_support/inflector"
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
###
|
||||
### configurable constants
|
||||
###
|
||||
|
||||
EXPANDED_SYMBOLS = {
|
||||
"+" => "plus",
|
||||
"@" => "at",
|
||||
}.freeze
|
||||
|
||||
CASK_FILE_EXTENSION = ".rb".freeze
|
||||
|
||||
# Hardcode App names that cannot be transformed automatically.
|
||||
# Example: in "x48.app", "x48" is not a version number.
|
||||
# The value in the hash should be a valid Cask token.
|
||||
APP_EXCEPTION_PATS = {
|
||||
# looks like a trailing version, but is not.
|
||||
%r{\Aiterm\Z}i => "iterm2",
|
||||
%r{\Aiterm2\Z}i => "iterm2",
|
||||
%r{\Apgadmin3\Z}i => "pgadmin3",
|
||||
%r{\Ax48\Z}i => "x48",
|
||||
%r{\Avitamin-r[\s\d\.]*\Z}i => "vitamin-r",
|
||||
%r{\Aimagealpha\Z}i => "imagealpha",
|
||||
# upstream is in the midst of changing branding
|
||||
%r{\Abitcoin-?qt\Z}i => "bitcoin-core",
|
||||
# "mac" cannot be separated from the name because it is in an English phrase
|
||||
%r{\Aplayonmac\Z}i => "playonmac",
|
||||
%r{\Acleanmymac[\s\d\.]*\Z}i => "cleanmymac",
|
||||
# arguably we should not have kept these two exceptions
|
||||
%r{\Akismac\Z}i => "kismac",
|
||||
%r{\Avoicemac\Z}i => "voicemac",
|
||||
}.freeze
|
||||
|
||||
# Preserve trailing patterns on App names that could be mistaken
|
||||
# for version numbers, etc
|
||||
PRESERVE_TRAILING_PATS = [
|
||||
%r{id3}i,
|
||||
%r{mp3}i,
|
||||
%r{3[\s-]*d}i,
|
||||
%r{diff3}i,
|
||||
%r{\A[^\d]+\+\Z}i,
|
||||
].freeze
|
||||
|
||||
# The code that employs these patterns against App names
|
||||
# - hacks a \b (word-break) between CamelCase and snake_case transitions
|
||||
# - anchors the pattern to end-of-string
|
||||
# - applies the patterns repeatedly until there is no match
|
||||
REMOVE_TRAILING_PATS = [
|
||||
# spaces
|
||||
%r{\s+}i,
|
||||
|
||||
# generic terms
|
||||
%r{\bapp}i,
|
||||
%r{\b(?:quick[\s-]*)?launcher}i,
|
||||
|
||||
# "mac", "for mac", "for OS X", "macOS", "for macOS".
|
||||
%r{\b(?:for)?[\s-]*mac(?:intosh|OS)?}i,
|
||||
%r{\b(?:for)?[\s-]*os[\s-]*x}i,
|
||||
|
||||
# hardware designations such as "for x86", "32-bit", "ppc"
|
||||
%r{(?:\bfor\s*)?x.?86}i,
|
||||
%r{(?:\bfor\s*)?\bppc}i,
|
||||
%r{(?:\bfor\s*)?\d+.?bits?}i,
|
||||
|
||||
# frameworks
|
||||
%r{\b(?:for)?[\s-]*(?:oracle|apple|sun)*[\s-]*(?:jvm|java|jre)}i,
|
||||
%r{\bgtk}i,
|
||||
%r{\bqt}i,
|
||||
%r{\bwx}i,
|
||||
%r{\bcocoa}i,
|
||||
|
||||
# localizations
|
||||
%r{en\s*-\s*us}i,
|
||||
|
||||
# version numbers
|
||||
%r{[^a-z0-9]+}i,
|
||||
%r{\b(?:version|alpha|beta|gamma|release|release.?candidate)(?:[\s\.\d-]*\d[\s\.\d-]*)?}i,
|
||||
%r{\b(?:v|ver|vsn|r|rc)[\s\.\d-]*\d[\s\.\d-]*}i,
|
||||
%r{\d+(?:[a-z\.]\d+)*}i,
|
||||
%r{\b\d+\s*[a-z]}i,
|
||||
%r{\d+\s*[a-c]}i, # constrained to a-c b/c of false positives
|
||||
].freeze
|
||||
|
||||
# Patterns which are permitted (undisturbed) following an interior version number
|
||||
AFTER_INTERIOR_VERSION_PATS = [
|
||||
%r{ce}i,
|
||||
%r{pro}i,
|
||||
%r{professional}i,
|
||||
%r{client}i,
|
||||
%r{server}i,
|
||||
%r{host}i,
|
||||
%r{viewer}i,
|
||||
%r{launcher}i,
|
||||
%r{installer}i,
|
||||
].freeze
|
||||
|
||||
###
|
||||
### classes
|
||||
###
|
||||
|
||||
class AppName < String
|
||||
def self.remove_trailing_pat
|
||||
@@remove_trailing_pat ||= %r{(?<=.)(?:#{REMOVE_TRAILING_PATS.join('|')})\Z}i
|
||||
end
|
||||
|
||||
def self.preserve_trailing_pat
|
||||
@@preserve_trailing_pat ||= %r{(?:#{PRESERVE_TRAILING_PATS.join('|')})\Z}i
|
||||
end
|
||||
|
||||
def self.after_interior_version_pat
|
||||
@@after_interior_version_pat ||= %r{(?:#{AFTER_INTERIOR_VERSION_PATS.join('|')})}i
|
||||
end
|
||||
|
||||
def english_from_app_bundle
|
||||
return self if ascii_only?
|
||||
return self unless File.exist?(self)
|
||||
|
||||
# check Info.plist CFBundleDisplayName
|
||||
bundle_name = Open3.popen3(*%w[
|
||||
/usr/libexec/PlistBuddy -c
|
||||
],
|
||||
"Print CFBundleDisplayName",
|
||||
Pathname.new(self).join("Contents", "Info.plist").to_s) do |_stdin, stdout, _stderr|
|
||||
begin
|
||||
stdout.gets.force_encoding("UTF-8").chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
|
||||
|
||||
# check Info.plist CFBundleName
|
||||
bundle_name = Open3.popen3(*%w[
|
||||
/usr/libexec/PlistBuddy -c
|
||||
],
|
||||
"Print CFBundleName",
|
||||
Pathname.new(self).join("Contents", "Info.plist").to_s) do |_stdin, stdout, _stderr|
|
||||
begin
|
||||
stdout.gets.force_encoding("UTF-8").chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
|
||||
|
||||
# check localization strings
|
||||
local_strings_file = Pathname.new(self).join("Contents", "Resources", "en.lproj", "InfoPlist.strings")
|
||||
local_strings_file = Pathname.new(self).join("Contents", "Resources", "English.lproj", "InfoPlist.strings") unless local_strings_file.exist?
|
||||
if local_strings_file.exist?
|
||||
bundle_name = File.open(local_strings_file, "r:UTF-16LE:UTF-8") do |fh|
|
||||
%r{\ACFBundle(?:Display)?Name\s*=\s*"(.*)";\Z}.match(fh.readlines.grep(%r{^CFBundle(?:Display)?Name\s*=\s*}).first) do |match|
|
||||
match.captures.first
|
||||
end
|
||||
end
|
||||
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
|
||||
end
|
||||
|
||||
# check Info.plist CFBundleExecutable
|
||||
bundle_name = Open3.popen3(*%w[
|
||||
/usr/libexec/PlistBuddy -c
|
||||
],
|
||||
"Print CFBundleExecutable",
|
||||
Pathname.new(self).join("Contents", "Info.plist").to_s) do |_stdin, stdout, _stderr|
|
||||
begin
|
||||
stdout.gets.force_encoding("UTF-8").chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def basename
|
||||
if Pathname.new(self).exist?
|
||||
AppName.new(Pathname.new(self).basename.to_s)
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
def remove_extension
|
||||
sub(%r{\.app\Z}i, "")
|
||||
end
|
||||
|
||||
def decompose_to_ascii
|
||||
# crudely (and incorrectly) decompose extended latin characters to ASCII
|
||||
return self if ascii_only?
|
||||
return self unless respond_to?(:mb_chars)
|
||||
AppName.new(mb_chars.normalize(:kd).each_char.select(&:ascii_only?).join)
|
||||
end
|
||||
|
||||
def hardcoded_exception
|
||||
APP_EXCEPTION_PATS.each do |regexp, exception|
|
||||
return AppName.new(exception) if regexp.match(self)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def insert_vertical_tabs_for_camel_case
|
||||
app_name = AppName.new(self)
|
||||
if app_name.sub!(%r{(#{self.class.preserve_trailing_pat})\Z}i, "")
|
||||
trailing = Regexp.last_match(1)
|
||||
end
|
||||
app_name.gsub!(%r{([^A-Z])([A-Z])}, "\\1\v\\2")
|
||||
app_name.sub!(%r{\Z}, trailing) if trailing
|
||||
app_name
|
||||
end
|
||||
|
||||
def insert_vertical_tabs_for_snake_case
|
||||
gsub(%r{_}, "\v")
|
||||
end
|
||||
|
||||
def clean_up_vertical_tabs
|
||||
gsub(%r{\v}, "")
|
||||
end
|
||||
|
||||
def remove_interior_versions!
|
||||
# done separately from REMOVE_TRAILING_PATS because this
|
||||
# requires a substitution with a backreference
|
||||
sub!(%r{(?<=.)[\.\d]+(#{self.class.after_interior_version_pat})\Z}i, '\1')
|
||||
sub!(%r{(?<=.)[\s\.\d-]*\d[\s\.\d-]*(#{self.class.after_interior_version_pat})\Z}i, '-\1')
|
||||
end
|
||||
|
||||
def remove_trailing_strings_and_versions
|
||||
app_name = insert_vertical_tabs_for_camel_case
|
||||
.insert_vertical_tabs_for_snake_case
|
||||
while self.class.remove_trailing_pat.match(app_name) &&
|
||||
!self.class.preserve_trailing_pat.match(app_name)
|
||||
app_name.sub!(self.class.remove_trailing_pat, "")
|
||||
end
|
||||
app_name.remove_interior_versions!
|
||||
app_name.clean_up_vertical_tabs
|
||||
end
|
||||
|
||||
def simplified
|
||||
return @simplified if @simplified
|
||||
@simplified = english_from_app_bundle
|
||||
.basename
|
||||
.decompose_to_ascii
|
||||
.remove_extension
|
||||
@simplified = @simplified.hardcoded_exception || @simplified.remove_trailing_strings_and_versions
|
||||
@simplified
|
||||
end
|
||||
end
|
||||
|
||||
class CaskFileName < String
|
||||
def spaces_to_hyphens
|
||||
gsub(%r{ +}, "-")
|
||||
end
|
||||
|
||||
def delete_invalid_chars
|
||||
gsub(%r{[^a-z0-9-]+}, "")
|
||||
end
|
||||
|
||||
def collapse_multiple_hyphens
|
||||
gsub(%r{--+}, "-")
|
||||
end
|
||||
|
||||
def delete_leading_hyphens
|
||||
gsub(%r{^--+}, "")
|
||||
end
|
||||
|
||||
def delete_hyphens_before_numbers
|
||||
gsub(%r{-([0-9])}, '\1')
|
||||
end
|
||||
|
||||
def spell_out_symbols
|
||||
cask_file_name = self
|
||||
EXPANDED_SYMBOLS.each do |k, v|
|
||||
cask_file_name.gsub!(k, " #{v} ")
|
||||
end
|
||||
cask_file_name.sub(%r{ +\Z}, "")
|
||||
end
|
||||
|
||||
def add_extension
|
||||
sub(%r{(?:#{escaped_cask_file_extension})?\Z}i, CASK_FILE_EXTENSION)
|
||||
end
|
||||
|
||||
def remove_extension
|
||||
sub(%r{#{escaped_cask_file_extension}\Z}i, "")
|
||||
end
|
||||
|
||||
def from_simplified_app_name
|
||||
return @from_simplified_app_name if @from_simplified_app_name
|
||||
@from_simplified_app_name = if APP_EXCEPTION_PATS.rassoc(remove_extension)
|
||||
remove_extension
|
||||
else
|
||||
remove_extension
|
||||
.downcase
|
||||
.spell_out_symbols
|
||||
.spaces_to_hyphens
|
||||
.delete_invalid_chars
|
||||
.collapse_multiple_hyphens
|
||||
.delete_leading_hyphens
|
||||
.delete_hyphens_before_numbers
|
||||
end
|
||||
raise "Could not determine Simplified App name" if @from_simplified_app_name.empty?
|
||||
@from_simplified_app_name.add_extension
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
### methods
|
||||
###
|
||||
|
||||
def project_root
|
||||
Dir.chdir File.dirname(File.expand_path(__FILE__))
|
||||
@git_root ||= Open3.popen3(*%w[
|
||||
git rev-parse --show-toplevel
|
||||
]) do |_stdin, stdout, _stderr|
|
||||
begin
|
||||
Pathname.new(stdout.gets.chomp)
|
||||
rescue
|
||||
raise "could not find project root"
|
||||
end
|
||||
end
|
||||
raise "could not find project root" unless @git_root.exist?
|
||||
@git_root
|
||||
end
|
||||
|
||||
def escaped_cask_file_extension
|
||||
@escaped_cask_file_extension ||= Regexp.escape(CASK_FILE_EXTENSION)
|
||||
end
|
||||
|
||||
def simplified_app_name
|
||||
@simplified_app_name ||= AppName.new(ARGV.first.dup.force_encoding("UTF-8")).simplified
|
||||
end
|
||||
|
||||
def cask_file_name
|
||||
@cask_file_name ||= CaskFileName.new(simplified_app_name).from_simplified_app_name
|
||||
end
|
||||
|
||||
def cask_token
|
||||
@cask_token ||= cask_file_name.remove_extension
|
||||
end
|
||||
|
||||
def warnings
|
||||
return @warnings if @warnings
|
||||
@warnings = []
|
||||
unless APP_EXCEPTION_PATS.rassoc(cask_token)
|
||||
if %r{\d} =~ cask_token
|
||||
@warnings.push "WARNING: '#{cask_token}' contains digits. Digits which are version numbers should be removed."
|
||||
end
|
||||
end
|
||||
filename = project_root.join("Casks", cask_file_name)
|
||||
if filename.exist?
|
||||
@warnings.push "WARNING: the file '#{filename}' already exists. Prepend the vendor name if this is not a duplicate."
|
||||
end
|
||||
@warnings
|
||||
end
|
||||
|
||||
def report
|
||||
puts "Proposed Simplified App name: #{simplified_app_name}" if $debug
|
||||
puts "Proposed token: #{cask_token}"
|
||||
puts "Proposed file name: #{cask_file_name}"
|
||||
puts "Cask Header Line: cask '#{cask_token}' do"
|
||||
unless warnings.empty?
|
||||
$stderr.puts "\n"
|
||||
$stderr.puts warnings
|
||||
$stderr.puts "\n"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
usage = <<-EOS
|
||||
Usage: generate_cask_token [ -debug ] <application.app>
|
||||
|
||||
Given an Application name or a path to an Application, propose a
|
||||
Cask token, filename, and header line.
|
||||
|
||||
With -debug, also provide the internal "Simplified App Name".
|
||||
|
||||
EOS
|
||||
|
||||
if ARGV.first =~ %r{^-+h(elp)?$}i
|
||||
puts usage
|
||||
exit 0
|
||||
end
|
||||
|
||||
if ARGV.first =~ %r{^-+debug?$}i
|
||||
$debug = 1
|
||||
ARGV.shift
|
||||
end
|
||||
|
||||
unless ARGV.length == 1
|
||||
puts usage
|
||||
exit 1
|
||||
end
|
||||
|
||||
report
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# generate_issue_template_urls
|
||||
#
|
||||
|
||||
###
|
||||
### dependencies
|
||||
###
|
||||
|
||||
require "erb"
|
||||
|
||||
###
|
||||
### constants
|
||||
###
|
||||
|
||||
BASE_URL = "https://github.com/caskroom/homebrew-cask/issues/new".freeze
|
||||
|
||||
###
|
||||
### methods
|
||||
###
|
||||
|
||||
def main(args)
|
||||
args.each do |file|
|
||||
File.read(file).scan(%r{(.*?)\n(.*)}m) do |title, body|
|
||||
puts generate_url(title, body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_url(title, body)
|
||||
encoded_title = url_encode(title)
|
||||
encoded_body = url_encode(body)
|
||||
if $debug
|
||||
puts "Encoded title: #{encoded_title}"
|
||||
puts "Encoded body: #{encoded_body}"
|
||||
end
|
||||
"#{BASE_URL}?title=#{encoded_title}&body=#{encoded_body}"
|
||||
end
|
||||
|
||||
def url_encode(unencoded_str)
|
||||
ERB::Util.url_encode(unencoded_str)
|
||||
end
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
usage = <<-EOS
|
||||
Usage: generate_issue_template_urls <issue_template.md> ...
|
||||
|
||||
Given one or more GitHub issue template files, generate encoded URLs for each
|
||||
and print, separated by newlines. The first line of a template file should be
|
||||
the issue title.
|
||||
|
||||
With -debug, print out the encoded title and body individually as well.
|
||||
|
||||
EOS
|
||||
|
||||
if ARGV.first =~ %r{^-+h(elp)?$}i
|
||||
puts usage
|
||||
exit 0
|
||||
end
|
||||
|
||||
if ARGV.first =~ %r{^-+debug?$}i
|
||||
$debug = 1
|
||||
ARGV.shift
|
||||
end
|
||||
|
||||
if ARGV.empty?
|
||||
puts usage
|
||||
exit 1
|
||||
end
|
||||
|
||||
main(ARGV)
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# irregular_cask_whitespace
|
||||
#
|
||||
# find irregular whitespace in Cask files
|
||||
#
|
||||
# notes
|
||||
#
|
||||
# requires a recent-ish Perl with Unicode support, probably 5.14
|
||||
# or better.
|
||||
#
|
||||
# bugs
|
||||
#
|
||||
# todo
|
||||
#
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
set +o histexpand
|
||||
set -o nounset
|
||||
shopt -s nocasematch
|
||||
shopt -s nullglob
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
warn () {
|
||||
local message="$@"
|
||||
message="${message//\\t/$'\011'}"
|
||||
message="${message//\\n/$'\012'}"
|
||||
message="${message%"${message##*[![:space:]]}"}"
|
||||
printf "%s\n" "$message" 1>&2
|
||||
}
|
||||
|
||||
die () {
|
||||
warn "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_irregular_cask_whitespace () {
|
||||
local directory="$1"
|
||||
cd "$directory" || die "Could not cd to '$directory'"
|
||||
|
||||
printf "# No trailing newline at EOF\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{[^\n]\z}s' -- ./*.rb
|
||||
|
||||
printf "\n# Extra trailing newline at EOF\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n{2}\z}s' -- ./*.rb
|
||||
|
||||
printf "\n# Final 'end' indented\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{ end\s+\z}s' -- ./*.rb
|
||||
|
||||
printf "\n# Extra newline before final end\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n\nend\s+\z}s' -- ./*.rb
|
||||
|
||||
printf "\n# Extra newline before header\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n\ncask\s+:v\d\S*\s+=>}s' -- ./*.rb
|
||||
|
||||
printf "\n# Extra newline after header\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{(?:\A|\n)cask\s+:v\d\S*\s+=>[^\n]+\n\n\s*(\S+)}s and $1 ne "if"' -- ./*.rb
|
||||
|
||||
printf "\n# No empty line before uninstall\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n[^\n]+\n +uninstall }s' -- ./*.rb
|
||||
|
||||
# todo?
|
||||
# printf "\n# No empty line before caveats\n"
|
||||
# perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n[^\n]+\n +caveats }s' -- ./*.rb
|
||||
|
||||
printf "\n# Extra interior newlines\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n{3,}}s' -- ./*.rb
|
||||
|
||||
printf "\n# Leading whitespace at BOF\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\A\s}s' -- ./*.rb
|
||||
|
||||
printf "\n# Trailing whitespace at EOL (includes Tab/CR)\n"
|
||||
perl -C32 -ne 'print " $ARGV\n" if m{\s\n}s' -- ./*.rb | sort | uniq
|
||||
|
||||
printf "\n# Tabs\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\t}s' -- ./*.rb
|
||||
|
||||
printf "\n# Carriage Returns\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\r}s' -- ./*.rb
|
||||
|
||||
printf "\n# Misc Control Characters\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{[\x00-\x08\x0B-\x0C\x0E\x1F]}s' -- ./*.rb
|
||||
|
||||
printf "\n# First indent not 2\n"
|
||||
perl -C32 -0777 -ne 's{\A(.*?\n)?cask\s+[^\n]+\n+}{}s; print " $ARGV\n" unless m{\A \S}s' -- ./*.rb
|
||||
|
||||
printf "\n# Indents not multiple of 2\n"
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n(?: ){0,} [a-z]}s' -- ./*.rb
|
||||
|
||||
printf "\n# Unicode Space Characters\n"
|
||||
# \x{0085}\x{0088}\x{0089}
|
||||
perl -C32 -0777 -ne 'print " $ARGV\n" if m{[\x{008a}\x{00a0}\x{1680}\x{180e}\x{2000}\x{2001}\x{2002}\x{2003}\x{2004}\x{2005}\x{2006}\x{2007}\x{2008}\x{2009}\x{200a}\x{200b}\x{2028}\x{2029}\x{202f}\x{205f}\x{2060}\x{3000}\x{feff}\x{e0020}]}s' -- ./*.rb
|
||||
|
||||
}
|
||||
|
||||
###
|
||||
### argument processing
|
||||
###
|
||||
|
||||
if [[ "${1:-}" =~ ^-+h(elp)?$ ]]; then
|
||||
printf "irregular_cask_whitespace <dir>
|
||||
|
||||
Find irregular whitespace in Cask files within <dir>
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
die "Single directory argument required"
|
||||
elif ! [ -d "$1" ]; then
|
||||
die "No directory found at '$1'"
|
||||
fi
|
||||
|
||||
###
|
||||
### dispatch
|
||||
###
|
||||
|
||||
_irregular_cask_whitespace "${@:-}"
|
||||
|
||||
#
|
||||
Executable
+166
@@ -0,0 +1,166 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_apps_in_pkg
|
||||
#
|
||||
|
||||
###
|
||||
### 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
|
||||
###
|
||||
|
||||
opt_lax=''
|
||||
opt_pkg=''
|
||||
pkgdir=''
|
||||
|
||||
# prefer GNU xargs
|
||||
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
warn () {
|
||||
local message="$@"
|
||||
message="${message//\\t/$'\011'}"
|
||||
message="${message//\\n/$'\012'}"
|
||||
message="${message%"${message##*[![:space:]]}"}"
|
||||
printf "%s\n" "$message" 1>&2
|
||||
}
|
||||
|
||||
die () {
|
||||
warn "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
app_source_1 () {
|
||||
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
|
||||
"$xargs" -0 /usr/bin/perl -0777 -ne \
|
||||
'while (m{<pkg-info[^\n]*install-location="/Applications".*?path\s*=\s*"([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
|
||||
}
|
||||
|
||||
app_source_2 () {
|
||||
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
|
||||
"$xargs" -0 /usr/bin/perl -0777 -ne \
|
||||
'while (m{<pkg-info[^\n]*install-location="/".*?path\s*=\s*"./Applications/([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
|
||||
}
|
||||
|
||||
app_source_3 () {
|
||||
/usr/bin/find "$pkgdir" -type d -name '*.app' | \
|
||||
perl -pe 's{\A.*/}{}';
|
||||
}
|
||||
|
||||
app_source_4 () {
|
||||
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
|
||||
"$xargs" -0 /usr/bin/perl -0777 -ne \
|
||||
'while (m{path\s*=\s*"([^"]+\.app)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
|
||||
}
|
||||
|
||||
app_source_5 () {
|
||||
/usr/bin/find "$pkgdir" -name Archive.pax.gz -print0 | \
|
||||
"$xargs" -0 -n1 -I{} /bin/bash -c \
|
||||
"/usr/bin/gunzip -c '{}' | /bin/pax | /usr/bin/egrep '\.app'" | \
|
||||
/usr/bin/perl -pe 's{\A.*/([^/]+\.app).*\Z}{$1}';
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
mark_up_sources () {
|
||||
/usr/bin/perl -pe 's{\n}{\000}sg' | \
|
||||
"$xargs" -0 -I{} -n1 /bin/bash -c \
|
||||
'printf "{}"; /bin/test -n "$(/usr/bin/find /Applications -type d -maxdepth 3 -name "{}" -print0; /usr/bin/find ~/Applications -type d -maxdepth 3 -name "{}")" && printf " (+)"; printf "\n"'
|
||||
}
|
||||
|
||||
process_args () {
|
||||
local arg
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
die "ERROR: A file argument is required"
|
||||
else
|
||||
opt_pkg="${!#}" # last arg
|
||||
fi
|
||||
for arg in "$@"; do
|
||||
if [[ $arg =~ ^-+h(elp)?$ ]]; then
|
||||
printf "list_apps_in_pkg [ -lax ] <file.pkg>
|
||||
|
||||
Given a package file, extract a list of candidate App names from
|
||||
inside the pkg, which may be useful for naming a Cask.
|
||||
|
||||
The given package file need not be installed.
|
||||
|
||||
If an App of the listed name is already installed in /Applications
|
||||
or ~/Applications, it will be followed by a plus symbol '(+)' in
|
||||
the output. This can be verified via 'ls' or the Finder.
|
||||
|
||||
Arguments
|
||||
|
||||
-lax Be less selective in looking for App names. Generate
|
||||
more, but less accurate, guesses.
|
||||
|
||||
Bugs: This script is imperfect.
|
||||
- It does not fully parse PackageInfo files
|
||||
- An App can be hidden within a nested archive and not found
|
||||
- Some pkg files simply don't contain any Apps
|
||||
|
||||
See CONTRIBUTING.md and 'man pkgutil' for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
elif [[ $arg =~ ^-+lax$ ]]; then
|
||||
opt_lax='true'
|
||||
elif [[ "$arg" = "$opt_pkg" ]]; then
|
||||
true
|
||||
else
|
||||
die "ERROR: Unknown argument '$arg'"
|
||||
fi
|
||||
done
|
||||
if [[ -h "$opt_pkg" ]]; then
|
||||
opt_pkg="$(/usr/bin/readlink "$opt_pkg")"
|
||||
fi
|
||||
if ! [[ -e "$opt_pkg" ]]; then
|
||||
die "ERROR: No such pkg file: '$opt_pkg'"
|
||||
fi
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_apps_in_pkg () {
|
||||
|
||||
if [[ -d "$opt_pkg" ]]; then
|
||||
pkgdir="$opt_pkg"
|
||||
else
|
||||
local tmpdir="$(/usr/bin/mktemp -d -t list_ids_in_pkg)"
|
||||
trap "/bin/rm -rf -- '$tmpdir'" EXIT
|
||||
pkgdir="$tmpdir/unpack"
|
||||
/usr/sbin/pkgutil --expand "$opt_pkg" "$tmpdir/unpack" "$pkgdir"
|
||||
fi
|
||||
|
||||
{
|
||||
# strings that look like App names (Something.app)
|
||||
app_source_1;
|
||||
app_source_2;
|
||||
app_source_3;
|
||||
if [[ -n "$opt_lax" ]]; then
|
||||
app_source_4;
|
||||
app_source_5;
|
||||
fi
|
||||
} | \
|
||||
merge_sources | \
|
||||
mark_up_sources
|
||||
}
|
||||
|
||||
process_args "${@}"
|
||||
|
||||
# dispatch main
|
||||
_list_apps_in_pkg
|
||||
|
||||
#
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_id_in_kext
|
||||
#
|
||||
|
||||
###
|
||||
### 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
|
||||
###
|
||||
|
||||
kextdir=''
|
||||
|
||||
# prefer GNU xargs
|
||||
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
bundle_id_source_1 () {
|
||||
/usr/bin/find "$kextdir" -name Info.plist -print0 | \
|
||||
"$xargs" -0 -I {} /usr/libexec/PlistBuddy {} -c 'Print :CFBundleIdentifier'
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
clean_sources () {
|
||||
/usr/bin/egrep -v '^com\.apple\.'
|
||||
}
|
||||
|
||||
mark_up_sources () {
|
||||
/usr/bin/perl -pe 's{\n}{\000}sg' | \
|
||||
"$xargs" -0 -I{} -n1 /bin/bash -c \
|
||||
'printf "{}"; /bin/test "$(/usr/sbin/kextstat -kl -b "{}" | /usr/bin/wc -l)" -gt 0 && printf " (+)"; printf "\n"'
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_id_in_kext () {
|
||||
|
||||
kextdir="$1"
|
||||
if [[ -h "$kextdir" ]]; then
|
||||
kextdir="$(/usr/bin/readlink "$kextdir")"
|
||||
fi
|
||||
|
||||
{
|
||||
# emit strings that look like bundle ids
|
||||
bundle_id_source_1;
|
||||
} | \
|
||||
clean_sources | \
|
||||
merge_sources | \
|
||||
mark_up_sources
|
||||
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
|
||||
printf "list_id_in_kext <file.kext>
|
||||
|
||||
Given a Kernel Extension (kext) bundle dir on disk, extract the
|
||||
associated kext Bundle ID, which may be useful in a Cask uninstall
|
||||
stanza, eg
|
||||
|
||||
uninstall :kext => 'kext.id.goes.here'
|
||||
|
||||
The kext need not be loaded for this script to work.
|
||||
|
||||
If a given kext is currently loaded, it will be followed by a plus
|
||||
symbol '(+)' in the output. This can be verified via the command
|
||||
|
||||
/usr/sbin/kextstat -kl -b 'kext.id.goes.here'
|
||||
|
||||
See CONTRIBUTING.md and 'man kextstat' for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_id_in_kext "${@}"
|
||||
|
||||
#
|
||||
Executable
+162
@@ -0,0 +1,162 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_ids_in_app
|
||||
#
|
||||
|
||||
###
|
||||
### 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
|
||||
###
|
||||
|
||||
appdir=''
|
||||
scriptdir="$(dirname "$0")"
|
||||
|
||||
# prefer GNU xargs
|
||||
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
bundle_id_source_1 () {
|
||||
/usr/bin/find "$appdir" -name Info.plist -print0 | \
|
||||
"$xargs" -0 -I {} /usr/libexec/PlistBuddy {} -c 'Print :CFBundleIdentifier'
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
clean_sources () {
|
||||
/usr/bin/egrep -v '^com\.apple\.' | \
|
||||
/usr/bin/egrep -vi '^org\.andymatuschak\.Sparkle' | \
|
||||
/usr/bin/egrep -vi '^(SDL|SDL_net|TDParseKit)$' | \
|
||||
/usr/bin/egrep -vi '^com\.growl\.(growlframework|WebKit|iCal|GrowlAction|GrowlLauncher|GrowlPlugins)' | \
|
||||
/usr/bin/egrep -vi '^com\.adobe\.(ACE|AGM|AXE8SharedExpat|AdobeExtendScript|AdobeScCore|AdobeXMPCore|BIB|BIBUtils|CoolType|ESD\.AdobeUpdaterLibFramework|JP2K|adobe_caps|AcrobatPlugin|AdobeResourceSynchronizer|ICUConverter|ICUData|acrobat\.assert|acrobat\.pdfviewerNPAPI|adobepdf417pmp|ahclientframework|datamatrixpmp|eulaframework|framework|linguistic|qrcodepmp)' | \
|
||||
/usr/bin/egrep -vi '^com\.microsoft\.(Automator|certificate\.framework|chart|converterlib|converters|excel\.pde|grammar|igx|mcp|merp|msls3|netlib|officeart|ole|oleo|powerplant|powerplantcore|powerpoint\.pde|speller|thesaurus|urlmon|wizard|wordforms|MSCommon|mbuinstrument_framework|mbukernel_framework|rdpkit)' | \
|
||||
/usr/bin/egrep -vi '^com\.google\.(Chrome\.framework|Chrome\.helper|Keystone|BreakpadFramework|GDataFramework|Reporter)' | \
|
||||
/usr/bin/egrep -vi '^atmo\.mac\.macho' | \
|
||||
/usr/bin/egrep -vi '^com\.3dconnexion\.driver\.client' | \
|
||||
/usr/bin/egrep -vi '^com\.Breakpad\.crash_report_sender' | \
|
||||
/usr/bin/egrep -vi '^com\.Cycling74\.driver\.Soundflower' | \
|
||||
/usr/bin/egrep -vi '^com\.HumbleDaisy\.HDCrashReporter' | \
|
||||
/usr/bin/egrep -vi '^com\.amazon\.JSONKit' | \
|
||||
/usr/bin/egrep -vi '^com\.bensyverson\..*dvmatte' | \
|
||||
/usr/bin/egrep -vi '^com\.binarymethod\.BGHUDAppKit' | \
|
||||
/usr/bin/egrep -vi '^com\.blacktree\.(QSCore|QSEffects|QSFoundation|QSInterface)' | \
|
||||
/usr/bin/egrep -vi '^com\.brandonwalkin\.BWToolkitFramework' | \
|
||||
/usr/bin/egrep -vi '^com\.cruzapp\.TDWebThumbnail' | \
|
||||
/usr/bin/egrep -vi '^com\.cycling74\.QTExportTool' | \
|
||||
/usr/bin/egrep -vi '^com\.fluidapp\.(BrowserBrowserPlugIn|FluidInstance|ThumbnailPlugIn)' | \
|
||||
/usr/bin/egrep -vi '^com\.github\.ObjectiveGit' | \
|
||||
/usr/bin/egrep -vi '^com\.heroku\.RedisAdapter' | \
|
||||
/usr/bin/egrep -vi '^com\.instinctivecode\.MGScopeBar' | \
|
||||
/usr/bin/egrep -vi '^com\.intel\.nw\.helper' | \
|
||||
/usr/bin/egrep -vi '^com\.joshaber\.RockemSockem' | \
|
||||
/usr/bin/egrep -vi '^com\.katidev\.KTUIKit' | \
|
||||
/usr/bin/egrep -vi '^com\.kirin\.plugin\.adapter' | \
|
||||
/usr/bin/egrep -vi '^com\.lextek\.onix' | \
|
||||
/usr/bin/egrep -vi '^com\.macromedia\.(Flash Player\.authplaylib|PepperFlashPlayer)' | \
|
||||
/usr/bin/egrep -vi '^com\.mainconcept\.mc\.enc\.avc' | \
|
||||
/usr/bin/egrep -vi '^com\.netscape\.(DefaultPlugin|MRJPlugin)' | \
|
||||
/usr/bin/egrep -vi '^com\.nxtbgthng\.JSONKit' | \
|
||||
/usr/bin/egrep -vi '^com\.omnigroup\.(OmniAppKit|OmniInspector|framework)' | \
|
||||
/usr/bin/egrep -vi '^com\.oracle\.java\..*\.jdk' | \
|
||||
/usr/bin/egrep -vi '^com\.panic\.(PanicCore|automator|CodaScriptPlugIn)' | \
|
||||
/usr/bin/egrep -vi '^com\.pixelespresso\.cocoafob' | \
|
||||
/usr/bin/egrep -vi '^com\.positivespinmedia\.(PSMTabBarControlFramework|PSMTabBarFramework)' | \
|
||||
/usr/bin/egrep -vi '^com\.softube\.(Amplifier|Cabinet)' | \
|
||||
/usr/bin/egrep -vi '^com\.sonic\.(AS_Storage|AuthorScriptHDMV)' | \
|
||||
/usr/bin/egrep -vi '^com\.soundcloud\.Share-on-SoundCloud' | \
|
||||
/usr/bin/egrep -vi '^com\.stuffit\.(format|sdk|stuffitcore)' | \
|
||||
/usr/bin/egrep -vi '^com\.sun\.Scintilla' | \
|
||||
/usr/bin/egrep -vi '^com\.yourcompany' | \
|
||||
/usr/bin/egrep -vi '^coop\.plausible\.(CrashReporter|PLWeakCompatibility)' | \
|
||||
/usr/bin/egrep -vi '^de\.buzzworks\.Quincy' | \
|
||||
/usr/bin/egrep -vi '^de\.dstoecker\.xadmaster' | \
|
||||
/usr/bin/egrep -vi '^isao\.sonobe\.OgreKit' | \
|
||||
/usr/bin/egrep -vi '^jp\.hmdt\.framework\.hmdtblkappkit' | \
|
||||
/usr/bin/egrep -vi '^net\.hockeyapp\.sdk\.mac' | \
|
||||
/usr/bin/egrep -vi '^net\.java\.openjdk\.jre' | \
|
||||
/usr/bin/egrep -vi '^net\.liquidx\.EyeTunes' | \
|
||||
/usr/bin/egrep -vi '^net\.sourceforge\.Log4Cocoa' | \
|
||||
/usr/bin/egrep -vi '^net\.sourceforge\.munt\.MT32Emu' | \
|
||||
/usr/bin/egrep -vi '^net\.sourceforge\.skim-app\.framework' | \
|
||||
/usr/bin/egrep -vi '^net\.wafflesoftware\.ShortcutRecorder\.framework' | \
|
||||
/usr/bin/egrep -vi '^org\.AFNetworking\.AFNetworking' | \
|
||||
/usr/bin/egrep -vi '^org\.boredzo\.(LMX|ISO8601DateFormatter)' | \
|
||||
/usr/bin/egrep -vi '^org\.dribin\.dave\.DDHidLib' | \
|
||||
/usr/bin/egrep -vi '^org\.linkbackproject\.LinkBack' | \
|
||||
/usr/bin/egrep -vi '^org\.mozilla\.(crashreporter|plugincontainer|universalchardet|updater)' | \
|
||||
/usr/bin/egrep -vi '^org\.python\.(python|PythonLauncher|buildapplet)' | \
|
||||
/usr/bin/egrep -vi '^org\.remotesensing\.libtiff' | \
|
||||
/usr/bin/egrep -vi '^org\.vafer\.FeedbackReporter' | \
|
||||
/usr/bin/egrep -vi '^org\.xiph\.(ogg|vorbis)' | \
|
||||
/usr/bin/egrep -vi '^se\.propellerheads\..*\.library$'
|
||||
|
||||
}
|
||||
|
||||
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""
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_ids_in_app () {
|
||||
|
||||
appdir="$1"
|
||||
if [[ -h "$appdir" ]]; then
|
||||
appdir="$(/usr/bin/readlink "$appdir")"
|
||||
fi
|
||||
|
||||
{
|
||||
# emit strings that look like bundle ids
|
||||
bundle_id_source_1;
|
||||
} | \
|
||||
clean_sources | \
|
||||
merge_sources | \
|
||||
mark_up_sources
|
||||
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
|
||||
printf "list_ids_in_app <path.app>
|
||||
|
||||
Given a Application (app) bundle directory on disk, extract the
|
||||
associated app Bundle ID, which may be useful in a Cask uninstall
|
||||
stanza, eg
|
||||
|
||||
uninstall quit: 'app.id.goes.here'
|
||||
|
||||
The app need not be running for this script to work.
|
||||
|
||||
Bundle IDs attributed to Apple and common developer frameworks
|
||||
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'
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_ids_in_app "${@}"
|
||||
|
||||
#
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_ids_in_pkg
|
||||
#
|
||||
|
||||
###
|
||||
### 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
|
||||
###
|
||||
|
||||
pkgdir=''
|
||||
|
||||
# prefer GNU xargs
|
||||
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
bundle_id_source_1 () {
|
||||
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
|
||||
"$xargs" -0 /usr/bin/perl -0777 -ne \
|
||||
'while (m{<pkg-info.*?\sid(?:entifier)?\s*=\s*"([^"]*?)"}sg) { print "$1\n" }'
|
||||
}
|
||||
|
||||
bundle_id_source_2 () {
|
||||
/usr/bin/find "$pkgdir" -name Info.plist -print0 | \
|
||||
"$xargs" -0 -I {} /usr/libexec/PlistBuddy {} -c 'Print :CFBundleIdentifier'
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
clean_sources () {
|
||||
/usr/bin/egrep -v '^com\.apple\.' | \
|
||||
/usr/bin/egrep -v 'sparkle\.finish-installation$'
|
||||
}
|
||||
|
||||
mark_up_sources () {
|
||||
/usr/bin/perl -pe 's{\n}{\000}sg' | \
|
||||
"$xargs" -0 -I{} -n1 /bin/bash -c \
|
||||
'printf "{}"; /usr/sbin/pkgutil --pkg-info "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_ids_in_pkg () {
|
||||
|
||||
if [[ -d "$1" ]]; then
|
||||
pkgdir="$1"
|
||||
if [[ -h "$pkgdir" ]]; then
|
||||
pkgdir="$(/usr/bin/readlink "$pkgdir")"
|
||||
fi
|
||||
else
|
||||
local tmpdir="$(/usr/bin/mktemp -d -t list_ids_in_pkg)"
|
||||
trap "/bin/rm -rf -- '$tmpdir'" EXIT
|
||||
pkgdir="$tmpdir/unpack"
|
||||
/usr/sbin/pkgutil --expand "$1" "$tmpdir/unpack" "$pkgdir"
|
||||
fi
|
||||
|
||||
{
|
||||
# emit strings that look like bundle ids
|
||||
bundle_id_source_1;
|
||||
bundle_id_source_2;
|
||||
} | \
|
||||
merge_sources | \
|
||||
clean_sources | \
|
||||
mark_up_sources
|
||||
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
|
||||
printf "list_ids_in_pkg <file.pkg>
|
||||
|
||||
Given a package file, extract a list of candidate Package IDs
|
||||
which may be useful in a Cask uninstall stanza, eg
|
||||
|
||||
uninstall pkgutil: 'package.id.goes.here'
|
||||
|
||||
The given package file need not be installed.
|
||||
|
||||
The output of this script should be overly inclusive -- not
|
||||
every candidate package id in the output will be needed at
|
||||
uninstall time.
|
||||
|
||||
Package IDs designated by Apple or common development frameworks
|
||||
will be excluded from the output.
|
||||
|
||||
If a package id is already installed, it will be followed by
|
||||
a plus symbol '(+)' in the output. This can be verified via
|
||||
the command
|
||||
|
||||
/usr/sbin/pkgutil --pkg-info 'package.id.goes.here'
|
||||
|
||||
See CONTRIBUTING.md and 'man pkgutil' for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_ids_in_pkg "${@}"
|
||||
|
||||
#
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/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{<key>\s*Label\s*</key>\s*<string>([^<]+?)</string>}sg) { print "$1\n" }'
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
clean_sources () {
|
||||
/usr/bin/egrep -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, eg
|
||||
|
||||
uninstall launchctl: 'job.id.goes.here'
|
||||
|
||||
Launchctl jobs attributed to Apple will be ommitted.
|
||||
|
||||
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 "${@}"
|
||||
|
||||
#
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_loaded_kext_ids
|
||||
#
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e # exit on any uncaught error
|
||||
set +o histexpand # don't expand history expressions
|
||||
shopt -s nocasematch # case-insensitive regular expressions
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_loaded_kext_ids () {
|
||||
/usr/sbin/kextstat -kl | \
|
||||
/usr/bin/cut -c53- | \
|
||||
/usr/bin/cut -f1 -d' ' | \
|
||||
/usr/bin/egrep -v '^com\.apple\.'
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ ]]; then
|
||||
printf "list_loaded_kext_ids
|
||||
|
||||
Print Bundle IDs for currently loaded Kernel Extensions (kexts)
|
||||
which may be useful in a Cask uninstall stanza, eg
|
||||
|
||||
uninstall kext: 'kext.bundle.id.goes.here'
|
||||
|
||||
Kexts attributed to Apple are excluded from the output.
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_loaded_kext_ids "${@}"
|
||||
|
||||
#
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_loaded_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
|
||||
###
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
launchjob_id_source_1 () {
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
/usr/bin/sudo -p 'Optionally give your sudo password: ' -- /bin/launchctl list | /usr/bin/cut -f3
|
||||
fi
|
||||
}
|
||||
|
||||
launchjob_id_source_2 () {
|
||||
/bin/launchctl list | /usr/bin/cut -f3
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
clean_sources () {
|
||||
/usr/bin/egrep -v '^Label$' | \
|
||||
/usr/bin/egrep -v '^com\.apple\.' | \
|
||||
/usr/bin/egrep -v '^0x[0-9a-f]+\.anonymous\.' | \
|
||||
/usr/bin/egrep -v '^\[0x' | \
|
||||
/usr/bin/egrep -v '\.[0-9]+$'
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_loaded_launchjob_ids () {
|
||||
|
||||
{
|
||||
launchjob_id_source_1;
|
||||
launchjob_id_source_2;
|
||||
} | \
|
||||
clean_sources | \
|
||||
merge_sources
|
||||
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ ]]; then
|
||||
printf "list_loaded_launchjob_ids
|
||||
|
||||
List IDs for currently-loaded launchctl jobs, which may be useful
|
||||
in a Cask uninstall stanza, eg
|
||||
|
||||
uninstall launchctl: 'job.id.goes.here'
|
||||
|
||||
If this command is not run as the superuser, you will be prompted
|
||||
for a password to run a subcommand using 'sudo'. The password is
|
||||
not required, but supplying it may reveal additional job ids. To
|
||||
skip using the password, press <return> repeatedly.
|
||||
|
||||
Launchctl jobs attributed to Apple are excluded from the output.
|
||||
|
||||
See CONTRIBUTING.md and 'man launchctl' for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_loaded_launchjob_ids "${@}"
|
||||
|
||||
#
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# list_login_items_for_app
|
||||
#
|
||||
|
||||
###
|
||||
### dependencies
|
||||
###
|
||||
|
||||
require "open3"
|
||||
|
||||
###
|
||||
### methods
|
||||
###
|
||||
|
||||
def usage
|
||||
<<-EOS
|
||||
Usage: list_login_items_for_app <path.app>
|
||||
|
||||
Given an Application (app) bundle directory on disk, find all
|
||||
login items associated with that app, which you can use in a
|
||||
Cask uninstall stanza, eg
|
||||
|
||||
uninstall login_item: 'login item name'
|
||||
|
||||
Note that you will likely need to have opened the app at least
|
||||
once for any login items to be present.
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
||||
EOS
|
||||
end
|
||||
|
||||
def process_args
|
||||
if ARGV.first =~ %r{^-+h(?:elp)?$}
|
||||
puts usage
|
||||
exit 0
|
||||
elsif ARGV.length == 1
|
||||
$app_path = ARGV.first
|
||||
else
|
||||
puts usage
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
def list_login_items_for_app(app_path)
|
||||
out, err, status = Open3.capture3(
|
||||
"/usr/bin/osascript", "-e",
|
||||
"tell application \"System Events\" to get the name of every login item " \
|
||||
"whose path contains \"#{File.basename(app_path)}\""
|
||||
)
|
||||
if status.exitstatus > 0
|
||||
$stderr.puts err
|
||||
exit status.exitstatus
|
||||
end
|
||||
puts out.gsub(", ", "\n")
|
||||
end
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
process_args
|
||||
list_login_items_for_app $app_path
|
||||
Executable
+126
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_payload_in_pkg
|
||||
#
|
||||
|
||||
###
|
||||
### 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
|
||||
###
|
||||
|
||||
pkg_arg=''
|
||||
tmp_boms=''
|
||||
|
||||
# prefer GNU xargs
|
||||
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
|
||||
|
||||
trap cleanup_tmp_boms EXIT
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
cleanup_tmp_boms () {
|
||||
if [[ -n "$tmp_boms" ]]; then
|
||||
# tmpfile ensures that rmdir -p is not too destructive
|
||||
local tmpfile="/tmp/list_payload_in_pkg.$$";
|
||||
/usr/bin/touch "$tmpfile";
|
||||
echo "$tmp_boms" | \
|
||||
/usr/bin/perl -pe 's{\n}{\000}sg' | \
|
||||
"$xargs" -0 /bin/rm -f --;
|
||||
{
|
||||
echo "$tmp_boms" | \
|
||||
/usr/bin/perl -pe 's{[^/]+\n}{\000}sg' | \
|
||||
"$xargs" -0 /bin/rmdir -p -- || true
|
||||
} 2>/dev/null
|
||||
/bin/rm -- "$tmpfile";
|
||||
fi
|
||||
}
|
||||
|
||||
bom_source_1 () {
|
||||
/usr/bin/find "$pkg_arg" -iname '*.pkg' -print0 | \
|
||||
"$xargs" -0 -I{} -n1 /usr/sbin/pkgutil --bom "{}" 2>/dev/null
|
||||
}
|
||||
|
||||
bom_source_2 () {
|
||||
/usr/bin/find "$pkg_arg" -name '*.bom'
|
||||
}
|
||||
|
||||
expand_sources () {
|
||||
/usr/bin/perl -pe 's{\n}{\000}sg' | \
|
||||
"$xargs" -0 lsbom --
|
||||
}
|
||||
|
||||
merge_sources () {
|
||||
/usr/bin/sort | /usr/bin/uniq
|
||||
}
|
||||
|
||||
clean_sources () {
|
||||
/usr/bin/cut -f1 | \
|
||||
/usr/bin/perl -pe 's{\A\.}{}' | \
|
||||
/usr/bin/egrep '.'
|
||||
}
|
||||
|
||||
mark_up_sources () {
|
||||
/usr/bin/perl -pe 's{\n}{\000}sg' | \
|
||||
"$xargs" -0 -I{} -n1 /bin/bash -c \
|
||||
'printf "{}"; /bin/test -e "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_payload_in_pkg () {
|
||||
|
||||
pkg_arg="$1"
|
||||
if [[ -h "$pkg_arg" ]]; then
|
||||
pkg_arg="$(/usr/bin/readlink "$pkg_arg")"
|
||||
fi
|
||||
|
||||
tmp_boms="$(bom_source_1)";
|
||||
{
|
||||
# find BOM files
|
||||
echo "$tmp_boms";
|
||||
bom_source_2;
|
||||
} | \
|
||||
expand_sources | \
|
||||
clean_sources | \
|
||||
merge_sources | \
|
||||
mark_up_sources
|
||||
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
|
||||
printf "list_payload_in_pkg <file.pkg>
|
||||
|
||||
Given a package file, show what files may be installed by that
|
||||
pkg, which may be useful when writing a Cask uninstall stanza.
|
||||
|
||||
The given package file need not be installed.
|
||||
|
||||
The output attempts to be overly inclusive. However, since
|
||||
pkg files are allowed to run arbitrary scripts, there can be
|
||||
no guarantee that the output is exact.
|
||||
|
||||
If a given file is already installed, it will be followed by
|
||||
a plus symbol '(+)' in the output.
|
||||
|
||||
See CONTRIBUTING.md and 'man pkgutil' for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_payload_in_pkg "${@}"
|
||||
|
||||
#
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_pkg_ids_by_regexp
|
||||
#
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e # exit on any uncaught error
|
||||
set +o histexpand # don't expand history expressions
|
||||
shopt -s nocasematch # case-insensitive regular expressions
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
warn () {
|
||||
local message="$@"
|
||||
message="${message//\\t/$'\011'}"
|
||||
message="${message//\\n/$'\012'}"
|
||||
message="${message%"${message##*[![:space:]]}"}"
|
||||
printf "%s\n" "$message" 1>&2
|
||||
}
|
||||
|
||||
die () {
|
||||
warn "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
fail_informatively () {
|
||||
local message="No match."
|
||||
if ! [[ "$1" =~ '*' ]]; then
|
||||
message="$message Suggestion: try '${1}.*'"
|
||||
fi
|
||||
die "$message"
|
||||
}
|
||||
|
||||
analyze_regexp () {
|
||||
if [[ "$1" =~ ^\^ ]]; then
|
||||
warn "Note: pkgutil regular expressions are implicitly anchored with '^' at start"
|
||||
fi
|
||||
if [[ "$1" =~ \$$ ]]; then
|
||||
warn "Note: pkgutil regular expressions are implicitly anchored with '$' at end"
|
||||
fi
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_pkg_ids_by_regexp () {
|
||||
analyze_regexp "$1"
|
||||
if ! /usr/sbin/pkgutil --pkgs="$1"; then
|
||||
fail_informatively "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ || $# -ne 1 ]]; then
|
||||
printf "list_pkg_ids_by_regexp <regexp>
|
||||
|
||||
Print pkg receipt IDs for installed packages matching a regular
|
||||
expression, which may be useful in a Cask uninstall stanza, eg
|
||||
|
||||
uninstall pkgutil: 'pkg.regexp.goes.here'
|
||||
|
||||
Unlike most other scripts in this directory, package IDs attributed to
|
||||
Apple are NOT excluded from the output. This is to avoid uninstalling
|
||||
essential system files due to an exuberant regexp.
|
||||
|
||||
For more information, see
|
||||
|
||||
https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/uninstall.md
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_pkg_ids_by_regexp "${@}"
|
||||
|
||||
#
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# list_recent_pkg_ids
|
||||
#
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e # exit on any uncaught error
|
||||
set +o histexpand # don't expand history expressions
|
||||
shopt -s nocasematch # case-insensitive regular expressions
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_list_recent_pkg_ids () {
|
||||
/bin/ls -t /var/db/receipts | \
|
||||
/usr/bin/egrep '\.plist$' | \
|
||||
/usr/bin/perl -pe 's{\A([^/]+)\.plist\Z}{$1}sg' | \
|
||||
/usr/bin/egrep -v '^com\.apple\.' | \
|
||||
/usr/bin/head -10
|
||||
}
|
||||
|
||||
# process args
|
||||
if [[ $1 =~ ^-+h(elp)?$ ]]; then
|
||||
printf "list_recent_pkg_ids
|
||||
|
||||
Print pkg receipt IDs for the 10 most-recently-installed packages,
|
||||
which may be useful in a Cask uninstall stanza, eg
|
||||
|
||||
uninstall pkgutil: 'pkg.receipt.id.goes.here'
|
||||
|
||||
Package IDs attributed to Apple are excluded from the output.
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
fi
|
||||
|
||||
# dispatch main
|
||||
_list_recent_pkg_ids "${@}"
|
||||
|
||||
#
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# list_running_app_ids
|
||||
#
|
||||
|
||||
###
|
||||
### dependencies
|
||||
###
|
||||
|
||||
require "open3"
|
||||
require "set"
|
||||
|
||||
###
|
||||
### globals
|
||||
###
|
||||
|
||||
$opt_test = nil
|
||||
|
||||
###
|
||||
### methods
|
||||
###
|
||||
|
||||
def check_ruby
|
||||
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
|
||||
end
|
||||
|
||||
def usage
|
||||
<<-EOS
|
||||
list_running_app_ids [ -t <bundle-id> ]
|
||||
|
||||
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 <bundle-id>", 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 =~ %r{^-+t(?:est)?$} && ARGV.length > 1
|
||||
ARGV.shift
|
||||
$opt_test = ARGV.shift
|
||||
elsif ARGV.first =~ %r{^-+h(?:elp)?$}
|
||||
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 > 0
|
||||
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)
|
||||
%r{^com\.apple\.}.match(bundle_id)
|
||||
end
|
||||
|
||||
def excluded_app_name(app_name)
|
||||
%r{^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!(%r{^(missing value)$}, '<\1>')
|
||||
running.add "#{bundle_id}\t#{app_name}"
|
||||
end
|
||||
|
||||
puts "bundle_id\tapp_name\n"
|
||||
puts "--------------------------------------\n"
|
||||
puts running.to_a.sort
|
||||
end
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
check_ruby
|
||||
process_args
|
||||
load_apps
|
||||
|
||||
if $opt_test
|
||||
exit test_app($opt_test)
|
||||
else
|
||||
report_apps
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user