#!/bin/bash

set -e

_sysroot="${SYSROOT}"

# Collect options from the command line
for i in "$@"; do
	case "$i" in
		--sysroot=*)
			_sysroot="${i#*=}"
			shift
			;;
		--)
			shift
			break
			;;
		--*)
			echo "$0: Unknown option: $i" >&2
			exit 1
			;;
		*)
			break
			;;
	esac
done

# Grab information about the bundle from the environment (if XCode) or make
# assumptions about the bundle layout (everywhere else)
_executable_path="${EXECUTABLE_PATH:-$1}"
if [ -n "${WRAPPER_NAME}" ]; then
	_wrapper_name="${WRAPPER_NAME}"
else
	_wrapper_name="${_executable_path%.app/*}"
	if [ "${_wrapper_name}" == "${_executable_path}" ]; then
		echo "Unable to derive bundle location from '${_wrapper_name}'!" >&2
		exit 1
	fi
	_wrapper_name="${_wrapper_name}.app"
fi
_contents_folder="${CONTENTS_FOLDER_PATH:-${_wrapper_name}/Contents}"
_frameworks_folder_path="${FRAMEWORKS_FOLDER_PATH:-${_contents_folder}/Frameworks}"

# Get tool names/paths from the environment in case we're cross compiling
_otool="${OTOOL:-otool}"
_install_name_tool="${INSTALL_NAME_TOOL:-install_name_tool}"

if [ -n "${TARGET_BUILD_DIR}" ]; then
	cd "${TARGET_BUILD_DIR}"
fi

echo "Bundling libraries..."

bundle_dependencies() {
	local _object_path="$1"
	local _library_name

	"${_otool}" -L "${_object_path}" | \
	awk '/^\t+\// { print $1 }' | \
	grep -v '@executable_path.*' | \
	while read _library_name; do
		local _library_path="${_library_name}"

		# If the library isn't available at the stored path, it may be
		# stored inside the sysroot (when cross-compiling for example)
		if [ ! -e "${_library_path}" -a -n "${_sysroot}" ]; then
			_library_path="${_sysroot}${_library_path}"
		fi
		# If the library still isn't available there, there might be a YAML
		# stub instead in more recent SDKs; if we find one of those, the
		# library is part of the base install and doesn't need to be bundled
		local _stub_path="${_library_path%.dylib}.tbd"
		if [ ! -e "${_library_path}" -a -e "${_stub_path}" ]; then
			continue
		fi

		# Stop bundling if a lib doesn't exist
		if [ ! -e "${_library_path}" ]; then
			echo "Cannot find ${_library_name}." >&2
			exit 1
		fi

		local _base="$(basename "${_library_name}")"
		local _bundle_path="${_frameworks_folder_path}/${_base}"

		local _id="@executable_path/../Frameworks/${_base}"

		# Skip if it's a library stub (because we can't change the install name
		# of those anyway)
		if file -b "${_library_path}" | grep -q 'shared library stub'; then
			continue
		fi

		# Change the depender reference unconditionally
		"${_install_name_tool}" -change "${_library_name}" "${_id}" "${_object_path}"

		# Don't fixup this lib if it is already bundled - no point in doing the
		# same work multiple times
		[ -e "${_bundle_path}" ] && continue

		echo "Bundling '${_library_path}' as '${_base}'..."
		cp "${_library_path}" "${_bundle_path}"
		chmod u+w "${_bundle_path}"

		# Set a new install name for this dylib
		"${_install_name_tool}" -id "${_id}" "${_bundle_path}"

		# Also change the reference inside the application itself
		if [ "${_executable_path}" != "${_object_path}" ]; then
			"${_install_name_tool}" -change "${_library_name}" "${_id}" "${_executable_path}"
		fi

		# And also recursively bundle the dependencies of this dependency.
		bundle_dependencies "${_bundle_path}"
	done
}

mkdir -p "${_frameworks_folder_path}"
bundle_dependencies "${_executable_path}"
