mirror of
https://github.com/kyleneideck/BackgroundMusic
synced 2024-11-26 06:00:17 +00:00
6a26afe47a
Fixes #107.
587 lines
20 KiB
Bash
Executable file
587 lines
20 KiB
Bash
Executable file
#!/bin/bash
|
|
# vim: tw=100:
|
|
|
|
# This file is part of Background Music.
|
|
#
|
|
# Background Music is free software: you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License as
|
|
# published by the Free Software Foundation, either version 2 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# Background Music is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
# build_and_install.sh
|
|
#
|
|
# Copyright © 2016 Kyle Neideck
|
|
# Copyright © 2016 Nick Jacques
|
|
#
|
|
# Builds and installs BGMApp, BGMDriver and BGMXPCHelper. Requires xcodebuild and Xcode.
|
|
#
|
|
|
|
# Safe mode
|
|
set -euo pipefail
|
|
IFS=$'\n\t'
|
|
|
|
# Subshells and function inherit the ERR trap
|
|
set -o errtrace
|
|
|
|
# Go to the project directory.
|
|
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
|
|
|
error_handler() {
|
|
local LAST_COMMAND="${BASH_COMMAND}" LAST_COMMAND_EXIT_STATUS=$?
|
|
|
|
# Log the error.
|
|
echo "Failure in ${0} at line ${1}. The last command was (probably)" >> ${LOG_FILE}
|
|
echo " ${LAST_COMMAND}" >> ${LOG_FILE}
|
|
echo "which exited with status ${LAST_COMMAND_EXIT_STATUS}." >> ${LOG_FILE}
|
|
echo "Error message: ${ERROR_MSG}" >> ${LOG_FILE}
|
|
echo >> ${LOG_FILE}
|
|
|
|
# Scrub username from log (and also real name just in case).
|
|
sed -i'tmp' "s/$(whoami)/[username removed]/g" ${LOG_FILE}
|
|
sed -i'tmp' "s/$(id -F)/[name removed]/g" ${LOG_FILE}
|
|
rm "${LOG_FILE}tmp"
|
|
|
|
# Print an error message.
|
|
echo "$(tput setaf 9)ERROR$(tput sgr0): Install failed at line $1 with the message:"
|
|
echo
|
|
echo -e "${ERROR_MSG}" >&2
|
|
echo >&2
|
|
echo "Feel free to report this. If you do, you'll probably want to include the" \
|
|
"build_and_install.log file from this directory ($(pwd)). But quickly skim through it" \
|
|
"first to check that it doesn't include any personal information. It shouldn't, but this" \
|
|
"is alpha software so you never know." >&2
|
|
echo >&2
|
|
echo "To try building and installing without this build script, see MANUAL-INSTALL.md." >&2
|
|
echo >&2
|
|
echo "You can also try ignoring compiler warnings with: $0 -w" >&2
|
|
|
|
# Finish logging debug info if the script fails early.
|
|
if ! [[ -z ${LOG_DEBUG_INFO_TASK_PID:-} ]]; then
|
|
wait ${LOG_DEBUG_INFO_TASK_PID}
|
|
fi
|
|
}
|
|
|
|
# Build for release by default. Use -d for a debug build.
|
|
CONFIGURATION=Release
|
|
#CONFIGURATION=Debug
|
|
|
|
# The default is to clean before installing because we want the log file to have roughly the same
|
|
# information after every build.
|
|
CLEAN=clean
|
|
|
|
XCODEBUILD_OPTIONS=""
|
|
|
|
CONTINUE_ON_ERROR=0
|
|
|
|
# Update .gitignore if you change this.
|
|
LOG_FILE=build_and_install.log
|
|
|
|
# Empty the log file
|
|
echo -n > ${LOG_FILE}
|
|
|
|
COREAUDIOD_PLIST="/System/Library/LaunchDaemons/com.apple.audio.coreaudiod.plist"
|
|
|
|
# TODO: Should (can?) we use xcodebuild to get these from the Xcode project rather than duplicating
|
|
# them?
|
|
APP_PATH="/Applications"
|
|
APP_DIR="Background Music.app"
|
|
DRIVER_PATH="/Library/Audio/Plug-Ins/HAL"
|
|
DRIVER_DIR="Background Music Device.driver"
|
|
XPC_HELPER_PATH="$(BGMApp/BGMXPCHelper/safe_install_dir.sh)"
|
|
XPC_HELPER_DIR="BGMXPCHelper.xpc"
|
|
|
|
GENERAL_ERROR_MSG="Internal script error. Probably a bug in this script."
|
|
BUILD_FAILED_ERROR_MSG="A build command failed. Probably a compilation error."
|
|
BGMAPP_FAILED_TO_START_ERROR_MSG="Background Music (${APP_PATH}/${APP_DIR}) didn't seem to start \
|
|
up. It might just be taking a while.
|
|
|
|
If it didn't install correctly, you'll need to open the Sound control panel in System Preferences \
|
|
and change your output device at least once. Your sound probably won't work until you do. (Or you \
|
|
restart your computer.)
|
|
|
|
If you only have one device, you can create a temporary one by opening \
|
|
\"/Applications/Utilities/Audio MIDI Setup.app\", clicking the plus button and choosing \"Create \
|
|
Multi-Output Device\"."
|
|
ERROR_MSG="${GENERAL_ERROR_MSG}"
|
|
|
|
XCODEBUILD="/usr/bin/xcodebuild"
|
|
if ! [[ -x "${XCODEBUILD}" ]]; then
|
|
XCODEBUILD=$(which xcodebuild || true)
|
|
fi
|
|
# This check is last because it takes 10 seconds or so if it fails.
|
|
if ! [[ -x "${XCODEBUILD}" ]]; then
|
|
XCODEBUILD=$(/usr/bin/xcrun --find xcodebuild &2>>${LOG_FILE} || true)
|
|
fi
|
|
|
|
# TODO: Update this when/if Xcode 6 is supported.
|
|
RECOMMENDED_MIN_XCODE_VERSION=7
|
|
|
|
usage() {
|
|
echo "Usage: $0 [options]" >&2
|
|
echo -e "\t-n Don't clean before building/installing." >&2
|
|
echo -e "\t-d Debug build. (Release is the default.)" >&2
|
|
echo -e "\t-w Ignore compiler warnings. (They're treated as errors by default.)" >&2
|
|
echo -e "\t-x [options] Extra options to pass to xcodebuild." >&2
|
|
echo -e "\t-c Continue on script errors. Might not be safe." >&2
|
|
echo -e "\t-h Print this usage statement." >&2
|
|
exit 1
|
|
}
|
|
|
|
bold_face() {
|
|
echo $(tput bold)$*$(tput sgr0)
|
|
}
|
|
|
|
# Takes a PID and returns 0 if the process is running.
|
|
is_alive() {
|
|
kill -0 $1 > /dev/null 2>&1 && return 0 || return 1
|
|
}
|
|
|
|
# Shows a "..." animation until the previous command finishes. Shows an error message and exits the
|
|
# script if the command fails. The return value will be the exit status of the command.
|
|
#
|
|
# Params:
|
|
# - The error message to show if the previous command fails.
|
|
# - An optional timeout in seconds.
|
|
show_spinner() {
|
|
set +e
|
|
trap - ERR
|
|
|
|
local PREV_COMMAND_PID=$!
|
|
|
|
# Get the previous command as a string, with variables resolved. Assumes that if the command has
|
|
# a child process we just want the text of the child process's command. (And that it only has
|
|
# one child.)
|
|
local CHILD_PID=$(pgrep -P ${PREV_COMMAND_PID} | head -n1 || echo ${PREV_COMMAND_PID})
|
|
local PREV_COMMAND_STRING=$(ps -o command= ${CHILD_PID})
|
|
local TIMEOUT=${2:-0}
|
|
|
|
exec 3>&1 # Creates an alias so the following subshell can print to stdout.
|
|
DID_TIMEOUT=$(
|
|
I=1
|
|
while (is_alive ${PREV_COMMAND_PID}) && \
|
|
([[ ${TIMEOUT} -lt 1 ]] || [[ $I -lt ${TIMEOUT} ]])
|
|
do
|
|
printf '.' >&3
|
|
sleep 1
|
|
# Erase after we've printed three dots. (\b is backspace.)
|
|
[[ $((I % 3)) -eq 0 ]] && printf '\b\b\b \b\b\b' >&3
|
|
((I++))
|
|
done
|
|
if [[ $I -eq ${TIMEOUT} ]]; then
|
|
kill ${PREV_COMMAND_PID} >> ${LOG_FILE} 2>&1
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi)
|
|
exec 3<&- # Close the file descriptor.
|
|
|
|
wait ${PREV_COMMAND_PID}
|
|
local EXIT_STATUS=$?
|
|
|
|
# Clean up the dots.
|
|
printf '\b\b\b \b\b\b'
|
|
|
|
# Print an error message if the command fails.
|
|
# (wait returns 127 if the process has already exited.)
|
|
if [[ ${EXIT_STATUS} -ne 0 ]] && [[ ${EXIT_STATUS} -ne 127 ]]; then
|
|
ERROR_MSG="$1"
|
|
if [[ ${DID_TIMEOUT} -eq 0 ]]; then
|
|
ERROR_MSG+="\n\nFailed command:
|
|
${PREV_COMMAND_STRING}"
|
|
fi
|
|
|
|
error_handler ${LINENO}
|
|
|
|
if [[ ${CONTINUE_ON_ERROR} -eq 0 ]]; then
|
|
exit ${EXIT_STATUS}
|
|
fi
|
|
fi
|
|
|
|
if [[ ${CONTINUE_ON_ERROR} -eq 0 ]]; then
|
|
set -e
|
|
trap 'error_handler ${LINENO}' ERR
|
|
fi
|
|
|
|
return ${EXIT_STATUS}
|
|
}
|
|
|
|
parse_options() {
|
|
while getopts ":ndwx:ch" opt; do
|
|
case $opt in
|
|
n)
|
|
CLEAN=""
|
|
;;
|
|
d)
|
|
CONFIGURATION="Debug"
|
|
;;
|
|
w)
|
|
# TODO: What if they also pass their own OTHER_CFLAGS with -x?
|
|
XCODEBUILD_OPTIONS="${XCODEBUILD_OPTIONS} OTHER_CFLAGS=\"-Wno-error\""
|
|
;;
|
|
x)
|
|
XCODEBUILD_OPTIONS="$OPTARG"
|
|
;;
|
|
c)
|
|
CONTINUE_ON_ERROR=1
|
|
echo "$(tput setaf 11)WARNING$(tput sgr0): Ignoring errors."
|
|
set +e
|
|
trap - ERR
|
|
;;
|
|
h)
|
|
usage
|
|
;;
|
|
\?)
|
|
echo "Invalid option: -$OPTARG" >&2
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Checks if $XCODEBUILD is a usable xcodebuild. Exits with an error status if it isn't.
|
|
check_xcode() {
|
|
RETURN=0
|
|
|
|
# First, check xcodebuild exists on the system an is an executable.
|
|
if ! [[ -x "${XCODEBUILD}" ]] || ! /usr/bin/xcode-select --print-path &>/dev/null || \
|
|
! pkgutil --pkg-info=com.apple.pkg.CLTools_Executables &>/dev/null; then
|
|
RETURN=1
|
|
fi
|
|
|
|
# Check that Xcode is installed, not just the command line tools.
|
|
if ! "${XCODEBUILD}" -version &>/dev/null; then
|
|
((RETURN+=2))
|
|
fi
|
|
|
|
# Check they've already accepted the Xcode license. This code is mostly copied from
|
|
# Homebrew/Library/Homebrew/brew.sh.
|
|
set +e
|
|
trap - ERR
|
|
|
|
XCRUN_OUTPUT="$(/usr/bin/xcrun clang 2>&1)" # Making this a local breaks $?. Not sure why.
|
|
local XCRUN_STATUS="$?"
|
|
if [[ ${RETURN} -eq 0 ]] && \
|
|
[[ "${XCRUN_STATUS}" -ne 0 ]] && \
|
|
( [[ "${XCRUN_OUTPUT}" = *license* ]] || [[ "${XCRUN_OUTPUT}" = *licence* ]] ); then
|
|
RETURN=4
|
|
fi
|
|
|
|
if [[ ${CONTINUE_ON_ERROR} -eq 0 ]]; then
|
|
set -e
|
|
trap 'error_handler ${LINENO}' ERR
|
|
fi
|
|
|
|
# Version check.
|
|
local XCODE_MAJOR_VERSION="$(echo ${XCODE_VERSION} | sed 's/\..*$//g')"
|
|
if [[ ${RETURN} -eq 0 ]] && \
|
|
[[ "${XCODE_MAJOR_VERSION}" -lt ${RECOMMENDED_MIN_XCODE_VERSION} ]]
|
|
then
|
|
RETURN=5
|
|
fi
|
|
|
|
exit ${RETURN}
|
|
}
|
|
|
|
# Expects CHECK_XCODE_TASK_PID to be set.
|
|
handle_check_xcode_result() {
|
|
if [[ -z ${HANDLED_CHECK_XCODE_RESULT:-} ]]; then
|
|
HANDLED_CHECK_XCODE_RESULT=1
|
|
# Wait for the Xcode checks to finish.
|
|
set +e
|
|
trap - ERR
|
|
wait ${CHECK_XCODE_TASK_PID}
|
|
CHECK_XCODE_TASK_STATUS=$?
|
|
if [[ ${CONTINUE_ON_ERROR} -eq 0 ]]; then
|
|
set -e
|
|
trap 'error_handler ${LINENO}' ERR
|
|
fi
|
|
|
|
# If there was a problem with Xcode/xcodebuild, print the error message and exit.
|
|
if [[ ${CHECK_XCODE_TASK_STATUS} -ne 0 ]]; then
|
|
handle_check_xcode_failure ${CHECK_XCODE_TASK_STATUS}
|
|
fi
|
|
fi
|
|
}
|
|
|
|
handle_check_xcode_failure() {
|
|
# No command line tools
|
|
if [[ $1 -eq 1 ]] || [[ $1 -eq 3 ]]; then
|
|
echo "$(tput setaf 9)ERROR$(tput sgr0): The Xcode Command Line Tools don't seem to be" \
|
|
"installed on your system." >&2
|
|
echo >&2
|
|
echo "If you have Xcode installed, you should be able to install them with" >&2
|
|
echo " xcode-select --install" >&2
|
|
echo "If not, you'll need to install Xcode (~9GB), because xcodebuild no longer works" \
|
|
"without it." >&2
|
|
echo >&2
|
|
fi
|
|
|
|
# No Xcode
|
|
if [[ $1 -eq 2 ]] || [[ $1 -eq 3 ]]; then
|
|
echo "$(tput setaf 9)ERROR$(tput sgr0): Unfortunately, Xcode (~9GB) is required to build" \
|
|
"Background Music, but ${XCODEBUILD} doesn't appear to be usable. You may need to" \
|
|
"tell the Xcode command line tools where your Xcode is installed to with" >&2
|
|
echo " xcode-select --switch /the/path/to/your/Xcode.app" >&2
|
|
echo >&2
|
|
echo "Output from ${XCODEBUILD}:" >&2
|
|
|
|
"${XCODEBUILD}" -version >&2 || true
|
|
|
|
echo >&2
|
|
fi
|
|
|
|
# Need to agree to the Xcode license
|
|
if [[ $1 -eq 4 ]]; then
|
|
echo "$(tput setaf 9)ERROR$(tput sgr0): You need to agree to the Xcode license before you" \
|
|
"can build Background Music. Run this command and then try again:" >&2
|
|
echo " sudo xcodebuild -license" >&2
|
|
fi
|
|
|
|
if [[ $1 -eq 5 ]]; then
|
|
# Xcode version is probably too old.
|
|
echo "$(tput setaf 11)WARNING$(tput sgr0): Your version of Xcode (${XCODE_VERSION}) may" \
|
|
"not be recent enough to build Background Music." >&2
|
|
fi
|
|
|
|
# Try to find Xcode and print a more useful error message.
|
|
if [[ $1 -lt 4 ]]; then
|
|
# Disable error handlers
|
|
set +e; trap - ERR
|
|
|
|
echo "Looking for Xcode..." >&2
|
|
XCODE_PATHS=$(mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode' || \
|
|
kMDItemCFBundleIdentifier == 'com.apple.Xcode'")
|
|
|
|
if [[ "${XCODE_PATHS}" != "" ]]; then
|
|
echo "It looks like you have Xcode installed to" >&2
|
|
echo "${XCODE_PATHS}" >&2
|
|
else
|
|
echo "Not found." >&2
|
|
fi
|
|
fi
|
|
|
|
# Exit with an error status, unless we only printed a warning or were told to continue anyway.
|
|
if [[ $1 -ne 5 ]] && [[ ${CONTINUE_ON_ERROR} -eq 0 ]]; then
|
|
exit "$1"
|
|
fi
|
|
}
|
|
|
|
log_debug_info() {
|
|
# Log some environment details, version numbers, etc. This takes a while, so we do it in the
|
|
# background.
|
|
|
|
(set +e; trap - ERR
|
|
echo "Background Music Build Log" >> ${LOG_FILE}
|
|
echo "----" >> ${LOG_FILE}
|
|
echo "Build script args: $*" >> ${LOG_FILE}
|
|
echo "System details:" >> ${LOG_FILE}
|
|
|
|
sw_vers >> ${LOG_FILE} 2>&1
|
|
# The same as uname -a, except without printing the nodename (for privacy).
|
|
uname -mrsv >> ${LOG_FILE} 2>&1
|
|
|
|
/bin/bash --version >> ${LOG_FILE} 2>&1
|
|
/usr/bin/env python --version >> ${LOG_FILE} 2>&1
|
|
|
|
echo "On git branch: $(git rev-parse --abbrev-ref HEAD 2>&1)" >> ${LOG_FILE}
|
|
echo "Most recent commit: $(git rev-parse HEAD 2>&1)" \
|
|
"(\"$(git show -s --format=%s HEAD 2>&1)\")" >> ${LOG_FILE}
|
|
|
|
echo "Using xcodebuild: ${XCODEBUILD}" >> ${LOG_FILE}
|
|
echo "Using BGMXPCHelper path: ${XPC_HELPER_PATH}" >> ${LOG_FILE}
|
|
|
|
xcode-select --version >> ${LOG_FILE} 2>&1
|
|
echo "Xcode path: $(xcode-select --print-path 2>&1)" >> ${LOG_FILE}
|
|
echo "Xcode version:" >> ${LOG_FILE}
|
|
xcodebuild -version >> ${LOG_FILE} 2>&1
|
|
echo "Xcode SDKs:" >> ${LOG_FILE}
|
|
xcodebuild -showsdks >> ${LOG_FILE} 2>&1
|
|
xcrun --version >> ${LOG_FILE} 2>&1
|
|
echo "Clang version:" >> ${LOG_FILE}
|
|
$(/usr/bin/xcrun --find clang 2>&1) --version >> ${LOG_FILE} 2>&1
|
|
|
|
echo "launchctl version: $(launchctl version 2>&1)" >> ${LOG_FILE}
|
|
echo "----" >> ${LOG_FILE}) &
|
|
|
|
LOG_DEBUG_INFO_TASK_PID=$!
|
|
}
|
|
|
|
# Register our handler so we can print a message and clean up if there's an error.
|
|
trap 'error_handler ${LINENO}' ERR
|
|
|
|
parse_options "$@"
|
|
|
|
# Warn if running as root.
|
|
if [[ $(id -u) -eq 0 ]]; then
|
|
echo "$(tput setaf 11)WARNING$(tput sgr0): This script is not intended to be run as root. Run" \
|
|
"it normally and it'll sudo when it needs to." >&2
|
|
fi
|
|
|
|
# Print initial message.
|
|
echo "$(bold_face About to install Background Music). Please pause all audio, if you can."
|
|
[[ "${CONFIGURATION}" == "Debug" ]] && echo "Debug build."
|
|
echo
|
|
echo "This script will install:"
|
|
echo " - ${APP_PATH}/${APP_DIR}"
|
|
echo " - ${DRIVER_PATH}/${DRIVER_DIR}"
|
|
echo " - ${XPC_HELPER_PATH}/${XPC_HELPER_DIR}"
|
|
echo " - /Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist"
|
|
echo
|
|
|
|
# Make sure Xcode and the command line tools are installed and recent enough.
|
|
XCODE_VERSION=$(${XCODEBUILD} -version | head -n 1 | awk '{ print $2 }' 2>/dev/null || echo 0)
|
|
check_xcode &
|
|
CHECK_XCODE_TASK_PID=$!
|
|
|
|
read -p "Continue (y/N)? " CONTINUE_INSTALLATION
|
|
|
|
if [[ "${CONTINUE_INSTALLATION}" != "y" ]] && [[ "${CONTINUE_INSTALLATION}" != "Y" ]]; then
|
|
echo "Installation cancelled."
|
|
exit 0
|
|
fi
|
|
|
|
# If the check_xcode process has already finished, we can check the result early.
|
|
if ! is_alive ${CHECK_XCODE_TASK_PID}; then
|
|
handle_check_xcode_result
|
|
fi
|
|
|
|
# Update the user's sudo timestamp. (Prompts the user for their password.)
|
|
# Don't call sudo -v if this is a Travis CI build.
|
|
if ([[ -z ${TRAVIS:-} ]] || [[ "${TRAVIS}" != true ]]) && ! sudo -v; then
|
|
echo "ERROR: This script must be run by a user with administrator (sudo) privileges." >&2
|
|
exit 1
|
|
fi
|
|
|
|
handle_check_xcode_result
|
|
|
|
log_debug_info $*
|
|
|
|
# BGMDriver
|
|
|
|
echo "[1/3] Installing the virtual audio device $(bold_face ${DRIVER_DIR}) to" \
|
|
"$(bold_face ${DRIVER_PATH})." \
|
|
| tee -a ${LOG_FILE}
|
|
|
|
# Disable the -e shell option and error trap for build commands so we can handle errors differently.
|
|
(set +e; trap - ERR
|
|
# Build Apple's PublicUtility classes as a static library.
|
|
sudo "${XCODEBUILD}" -project BGMDriver/BGMDriver.xcodeproj \
|
|
-target "PublicUtility" \
|
|
-configuration ${CONFIGURATION} \
|
|
RUN_CLANG_STATIC_ANALYZER=0 \
|
|
${XCODEBUILD_OPTIONS} \
|
|
${CLEAN} build >> ${LOG_FILE} 2>&1) &
|
|
|
|
(set +e; trap - ERR
|
|
# Build and install BGMDriver
|
|
# TODO: Should these use -scheme instead?
|
|
sudo "${XCODEBUILD}" -project BGMDriver/BGMDriver.xcodeproj \
|
|
-target "Background Music Device" \
|
|
-configuration ${CONFIGURATION} \
|
|
RUN_CLANG_STATIC_ANALYZER=0 \
|
|
DSTROOT="/" \
|
|
${XCODEBUILD_OPTIONS} \
|
|
${CLEAN} install >> ${LOG_FILE} 2>&1) &
|
|
|
|
show_spinner "${BUILD_FAILED_ERROR_MSG}"
|
|
|
|
# BGMXPCHelper
|
|
|
|
echo "[2/3] Installing $(bold_face ${XPC_HELPER_DIR}) to $(bold_face ${XPC_HELPER_PATH})." \
|
|
| tee -a ${LOG_FILE}
|
|
|
|
(set +e; trap - ERR
|
|
sudo "${XCODEBUILD}" -project BGMApp/BGMApp.xcodeproj \
|
|
-target BGMXPCHelper \
|
|
-configuration ${CONFIGURATION} \
|
|
RUN_CLANG_STATIC_ANALYZER=0 \
|
|
DSTROOT="/" \
|
|
INSTALL_PATH="${XPC_HELPER_PATH}" \
|
|
${XCODEBUILD_OPTIONS} \
|
|
${CLEAN} install >> ${LOG_FILE} 2>&1) &
|
|
|
|
show_spinner "${BUILD_FAILED_ERROR_MSG}"
|
|
|
|
# BGMApp
|
|
|
|
echo "[3/3] Installing $(bold_face ${APP_DIR}) to $(bold_face ${APP_PATH})." \
|
|
| tee -a ${LOG_FILE}
|
|
|
|
(set +e; trap - ERR
|
|
sudo "${XCODEBUILD}" -project BGMApp/BGMApp.xcodeproj \
|
|
-target "Background Music" \
|
|
-configuration ${CONFIGURATION} \
|
|
RUN_CLANG_STATIC_ANALYZER=0 \
|
|
DSTROOT="/" \
|
|
${XCODEBUILD_OPTIONS} \
|
|
${CLEAN} install >> ${LOG_FILE} 2>&1) &
|
|
|
|
show_spinner "${BUILD_FAILED_ERROR_MSG}"
|
|
|
|
# Fix Background Music.app owner/group.
|
|
#
|
|
# We have to run xcodebuild as root to install BGMXPCHelper because it installs to directories
|
|
# owned by root. But that means the build directory gets created by root, and since BGMApp uses the
|
|
# same build directory we have to run xcodebuild as root to install BGMApp as well.
|
|
#
|
|
# TODO: Can't we just chown -R the build dir before we install BGMApp? Then we wouldn't have to
|
|
# install BGMApp as root. (But maybe still handle the unlikely case of APP_PATH not being
|
|
# user-writable.)
|
|
sudo chown -R "$(whoami):admin" "${APP_PATH}/${APP_DIR}"
|
|
|
|
# Fix the build directories' owner/group. This is mainly so the whole source directory can be
|
|
# deleted easily after installing.
|
|
sudo chown -R "$(whoami):admin" "BGMApp/build" "BGMDriver/build"
|
|
|
|
# Restart coreaudiod.
|
|
|
|
echo "Restarting coreaudiod to load the virtual audio device." \
|
|
| tee -a ${LOG_FILE}
|
|
|
|
# The extra or-clauses are fallback versions of the command that restarts coreaudiod. Apparently
|
|
# some of these commands don't work with older versions of launchctl, so I figure there's no harm in
|
|
# trying a bunch of different ways (which should all work).
|
|
(sudo launchctl kill SIGTERM system/com.apple.audio.coreaudiod &>/dev/null || \
|
|
sudo launchctl kill TERM system/com.apple.audio.coreaudiod &>/dev/null || \
|
|
sudo launchctl kill 15 system/com.apple.audio.coreaudiod &>/dev/null || \
|
|
sudo launchctl kill -15 system/com.apple.audio.coreaudiod &>/dev/null || \
|
|
(sudo launchctl unload "${COREAUDIOD_PLIST}" &>/dev/null && \
|
|
sudo launchctl load "${COREAUDIOD_PLIST}" &>/dev/null) || \
|
|
sudo killall coreaudiod &>/dev/null) && \
|
|
sleep 5
|
|
|
|
# Invalidate sudo ticket
|
|
sudo -k
|
|
|
|
# Open BGMApp.
|
|
#
|
|
# I'd rather not open BGMApp here, or at least ask first, but you have to change your default audio
|
|
# device after restarting coreaudiod and this is the easiest way.
|
|
echo "Launching Background Music."
|
|
|
|
ERROR_MSG="${BGMAPP_FAILED_TO_START_ERROR_MSG}"
|
|
open "${APP_PATH}/${APP_DIR}"
|
|
|
|
# Ignore script errors from this point.
|
|
set +e
|
|
trap - ERR
|
|
|
|
# Wait up to 5 seconds for Background Music to start.
|
|
(trap 'exit 1' TERM
|
|
while ! (ps -Ao ucomm= | grep 'Background Music' > /dev/null); do
|
|
sleep 1
|
|
done) &
|
|
show_spinner "${BGMAPP_FAILED_TO_START_ERROR_MSG}" 5
|
|
|
|
echo "Done."
|
|
|
|
|