Skip to content

Instantly share code, notes, and snippets.

@n8henrie
Created March 8, 2022 03:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save n8henrie/0fa76f46238116ab527061aeb2e81450 to your computer and use it in GitHub Desktop.
Save n8henrie/0fa76f46238116ab527061aeb2e81450 to your computer and use it in GitHub Desktop.
Convenience script to build a Quicksilver plugin from CLI
#!/bin/bash
#####
# build-plugin.sh
# bash 3.2-compatible convenience script to:
# - search by partial name for a plugin in the `QSPLUGINS` subdirectory
# (default `./QSPlugins`)
# - clean plugin directory
# - clean QS directory
# - `rm -rf /tmp/QS`
# - build Quicksilver (loop until it succeeds)
# - build plugin
# Usage: build-plugin.sh partialpluginname [configuration]
# Arguments:
# - partialpluginname: case-insensitive, will fail on multiple matches
# Options:
# - configuration: Debug (default) or Release
#####
set -Eeuf -o pipefail
set -x
readonly QS_SOURCE_ROOT="${QS_SOURCE_ROOT:-"${HOME}"/git/quicksilver/Quicksilver}"
readonly QSPLUGINS="${QSPLUGINS:-./QSPlugins}"
log() {
echo "$*" > /dev/stderr
}
err() {
log "error: $*"
exit 1
}
json() {
# Usage: stdin is json content, $1 is python-formatted query
# Example: `xcodebuild -list -json | json '["project"]["configurations"][0]'`
python3 -c '
import json
import sys
stdin = sys.stdin.read()
content = json.loads(stdin)
json_keys = sys.argv[1]
output = eval(f"{content}{json_keys}")
# Strips quotes if there is a simple result
if isinstance(output, str):
print(output)
# Pretty-print arrays and dicts
else:
print(json.dumps(output, indent=4))
' "$1"
}
build_quicksilver() {
local configuration
configuration=$1
pushd "${QS_SOURCE_ROOT}"
open -g Quicksilver.xcodeproj
xcodebuild -quiet clean
while [[ ! -x "/tmp/QS/build/${configuration}/Quicksilver.app/Contents/MacOS/Quicksilver" ]]; do
xcodebuild \
-quiet \
-destination generic/platform=macos \
-configuration "${configuration}" \
-scheme 'Quicksilver Distribution' \
build || true
done
popd
}
find_plugin() {
local plugin_name target_plugin
plugin_name=$1
# Workaround for no mapfile in bash 3, preserving compatibility with /bin/bash
target_plugin=()
while read -r -d '' target; do
target_plugin+=("${target}")
done < <(
find "${QSPLUGINS}" \
-maxdepth 1 \
-mindepth 1 \
-type d \
-iname "*${plugin_name}*" \
-print0
)
if [[ "${#target_plugin[@]}" -ne 1 ]]; then
err "possible matches for plugin -- ${plugin_name} -- ${target_plugin[*]}"
fi
plugindir="${target_plugin[0]}"
echo "${plugindir}"
}
clean_plugin() {
local plugindir
plugindir=$1
pushd "${plugindir}"
xcodebuild -quiet clean
}
build_plugin() {
local plugindir configuration
plugindir=$1
configuration=$2
project=$(find . -maxdepth 1 -name '*.xcodeproj' -not -iname "*test.xcodeproj" -print -quit)
if [[ -z "${project}" ]]; then
scheme_list=$(xcodebuild -list -json || true)
else
scheme_list=$(xcodebuild -list -json -project "${project}")
fi
if [[ -z "${scheme_list}" ]]; then
err "unable to determine scheme list"
fi
scheme=$(json '["project"]["targets"][0]' <<< "${scheme_list}")
log "Using default scheme: ${scheme}"
open -g "${project}"
# Absence of a project can still build, but will error if `-project` is specified
opts=(-configuration "${configuration}" -scheme "${scheme}")
if [[ -n "${project}" ]]; then
opts+=(-project "${project}")
fi
SETTINGS=$(xcodebuild "${opts[@]}" -showBuildSettings -json)
xcodebuild build -quiet "${opts[@]}"
FULL_PRODUCT_NAME=$(json '[0]["buildSettings"]["FULL_PRODUCT_NAME"]' <<< "${SETTINGS}")
log "Built ${FULL_PRODUCT_NAME} successfully"
}
main() {
local plugin configuration
plugin=$(find_plugin "$1")
configuration=${2-"Debug"}
# Sometimes still fails even with `-rf`
rm -rf /tmp/QS
clean_plugin "${plugin}"
build_quicksilver "${configuration}"
build_plugin "${plugin}" "${configuration}"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment