From 3ba3e6e01c406624adf2429507e5f0890b765f85 Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Thu, 25 Jul 2024 17:35:57 +0100 Subject: [PATCH] JAL-3631 Comprehensive install shell script for macos --- utils/install4j/macos-install-jalview.sh | 302 ++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100755 utils/install4j/macos-install-jalview.sh diff --git a/utils/install4j/macos-install-jalview.sh b/utils/install4j/macos-install-jalview.sh new file mode 100755 index 0000000..b91f9ca --- /dev/null +++ b/utils/install4j/macos-install-jalview.sh @@ -0,0 +1,302 @@ +#!/usr/bin/env bash + +usage() { + echo "Usage: $( basename $0 ) [-h] [ [-d] [-m arch] [-c channel] | [-i filename] ] [-a folder] [-u] [-U] [-S] [-P] [-R]" + echo "" + echo " This script downloads and installs Jalview in macOS, or installs from a previously downloaded Jalview DMG file." + echo " One of -d or -i should be specified, whichever comes last is used." + echo " Default behaviour with -d is to download the latest release version of Jalview for your architecture and install" + echo " the .app in /Applications with user-space updates enabled." + echo " These can be adjusted with the following options." + echo "" + echo " -h Show help" + echo " -d Download the latest DMG for the channel" + echo " -m arch (with -d) Download specific JVM architecture. Should be one of 'arm64' or 'x86_64' (defaults to \`uname -m\`)" + echo " -c channel (with -d) Download from channel. Should be one of 'release', 'test-release', 'develop' (defaults to 'release')." + echo " -i filename Use filename as DMG image file instead of downloading." + echo " -a folder Install the application .app bundle in folder (default '/Applications')." + echo "" + echo " Advanced options:" + echo "" + echo " -u template Use template for user-space updates path (defaults to '~/Library/Application Support/Jalview-Desktop')." + echo " template should contain one of: a leading '~/', '%u' (user's username) or '%h' (user's home path)." + echo " -U Disable user-space updates (updates will be attempted in the installation folder)." + echo " -S Disable all user-space and installation updates." + echo " -P Do not add the jalview command-line path to /etc/paths.d." + echo " -R Do not perform the check for root privileges." + echo " -t tmpdir Use tmpdir for installation files (defaults to /tmp)" +} + +# check OS +UOS="$(uname -s)" +if [ "$UOS" != "Darwin" ]; then + echo "This install script is for macOS." + echo "Jalview can be installed on other OSes using the installers found at" + echo "https://www.jalview.org/download/" + exit 1 +fi + +# set defaults +DOWNLOAD=0 +UARCH=$(uname -m) +CHANNEL="release" +DMGFILE="" +INSTALLERNAME="$(basename $0)" +APPLICATIONFOLDER="/Applications" +USERAPPDIRTEMPLATE="" +DISABLEUSERAPPDIR=0 +DISABLEALLUPDATES=0 +DISABLEGLOBALPATH=0 +DISABLEROOTCHECK=0 +USETEMPDIR="" +TMP="/tmp" + +# set options +while getopts "hdi:a:u:c:USPR" opt; do + case ${opt} in + h) + usage + exit 0 + ;; + d) + DOWNLOAD=1 + ;; + m) + UARCH="${OPTARG}" + ;; + c) + CHANNEL="${OPTARG}" + ;; + i) + DMGFILE="${OPTARG}" + DOWNLOAD=0 + ;; + a) + APPLICATIONFOLDER="${OPTARG}" + ;; + u) + USERAPPDIRTEMPLATE="${OPTARG}" + ;; + U) + DISABLEUSERAPPDIR=1 + ;; + S) + DISABLEALLUPDATES=1 + ;; + P) + DISABLEGLOBALPATH=1 + ;; + R) + DISABLEROOTCHECK=1 + ;; + t) + TMP="${OPTARG}" + ;; + *) + echo "Unrecognised option. Run with -h for help." + exit 2 + ;; + esac +done + +# no -d or -i arguments +if [ "${DOWNLOAD}" = 0 -a -z "${DMGFILE}" ]; then + usage + exit 0 +fi + +# root permissions check +if [ "${DISABLEROOTCHECK}" != 1 -a "${EUID}" != 0 ]; then + echo "This script should be run with root permissions, or with -R." + exit 5 +fi + +# check channel +case "$CHANNEL" in + release|test-release|develop) + echo "Using channel ${CHANNEL}" + ;; + *) + echo "-c channel must be one of 'release', 'test-release' or 'develop'" + exit 3 + ;; +esac + +# convert uarch to jarch +case $UARCH in + x86_64) + JARCH=x64 + ;; + arm64) + JARCH=aarch64 + ;; + *) + echo "Unknown architecture '$UARCH'. Exiting." + exit 4; + ;; +esac + +# dir for downloads and volume mount +TEMPDIR=$(mktemp -d -p "${TMP}" -t "${INSTALLERNAME%.sh}_${CHANNEL}") +echo "Using directory '${TEMPDIR}' to download/mount disk image" +FILEBASE="${TEMPDIR}/jalview-${CHANNEL}-latest-macos-${JARCH}" +VOLUMEDIR="${FILEBASE}.vol" + +if [ "${DOWNLOAD}" = 1 ]; then + DMGFILE="${FILEBASE}.dmg" + SHA256="" + + URL="https://www.jalview.org/downloads/${CHANNEL}/installer/macos-${JARCH}" + + echo "Downloading '${URL}' to '${DMGFILE}'" + curl -f -L -o "${DMGFILE}" "${URL}" + [ $? != 0 ] && echo "Could not download '$URL' to '$DMGFILE'" && exit 6 + SHA256=$( curl -f -s -L "${URL}.sha256" ) + [ $? != 0 ] && echo "Could not download '$URL.sha256'" && exit 7 + + CHECK=$( shasum -a 256 "${DMGFILE}" | cut -d" " -f1 ) + if [ "${CHECK}" = "${SHA256}" ]; then + echo "Downloaded file '$DMGFILE' checksum matches downloaded checksum '$SHA256'" + else + echo "Downloaded file '$DMGFILE' checksum does not match downloaded checksum '$SHA256'" + exit 8 + fi +fi + +# mount the DMG image +hdiutil attach -mountpoint "${VOLUMEDIR}" "${DMGFILE}" +[ $? != 0 ] && echo "Could not mount '${DMGFILE}' on mount point '${VOLUMEDIR}'" && exit 9 + +# difficult to use a wildcard for a non-user-readable folder without inserting sudo directly into the command +# i.e. what I really want to do here is +# APP=$( sudo sh -c "ls -1d ${VOLUMEDIR}/Jalview*.app" | head -1 ) +# but don't want to put sudo in the script because of the -R option. We'll loop through instead. +VOLUMEFILES=$( ls -1 ${VOLUMEDIR} ) +while IFS= read -r VOLUMEFILE; do + FILE=$( basename "${VOLUMEFILE}" ) + if [ "${FILE}" != "${FILE#Jalview}" -a "${FILE}" != "${FILE%.app}" ]; then + APP="${FILE}" + break + fi +done <<< "$VOLUMEFILES" +[ -z "${APP}" ] && echo "Could not find Jalview\*.app in the volume '${VOLUMEDIR}'" && exit 10 + +APPNAME=$( basename "$APP" ) + +# ensure no trailing slash on APPNAME or APPLICATIONFOLDER (important for rsync) +while [ "${APPLICATIONFOLDER}" != "${APPLICATIONFOLDER%/}" -a "${APPLICATIONFOLDER}" != "/" ]; do + APPLICATIONFOLDER=${APPLICATIONFOLDER%/} +done +while [ "${APPNAME}" != "${APPNAME%/}" ]; do + APPNAME=${APPNAME%/} +done +[ -z "${APPNAME}" ] && echo "Could not find suitable Jalview\*.app in the volume '${VOLUMEDIR}'" && exit 11 + +# rsync .app from mounted volume to application folder +rsync -avh --delete "${VOLUMEDIR}/${APPNAME}" "${APPLICATIONFOLDER}/" +[ $? != 0 ] && echo "Possible problem when rsyncing '${APP}' to '${APPLICATIONFOLDER}'" && exit 12 + +EXIT=0 +declare -a WARNINGS=() +addwarning() { + W=$1 + N=$2 + echo "$W" + WARNINGS=( "${WARNINGS[@]}" "$W" ) + [ "${EXIT}" = 0 ] && EXIT=$N +} + +# unmount the DMG image +hdiutil detach "${VOLUMEDIR}" || addwarning "Possible problem when unmounting/deleting '${VOLUMEDIR}'. I'm continuing the install but you should look at it later." 13 + +# delete the image file and temp dir +if [ "${DOWNLOAD}" = 1 ]; then + rm "${DMGFILE}" +fi +rmdir "${TEMPDIR}" + +VMOPTIONS="${APPLICATIONFOLDER}/${APPNAME}/Contents/vmoptions.txt" +VMOPTIONS_COMMENT=$( cat << EOM +# +# Jalview specific options below +EOM +) + +# -Dnouserdefaultappdir=false +if [ "${DISABLEUSERAPPDIR}" = 1 ]; then + VMOPTIONS_USERAPPDIR=$( cat << EOM +# +# Comment out the following line to allow user-space updates +-Dnouserdefaultappdir=true +EOM +) +else + VMOPTIONS_USERAPPDIR=$( cat << EOM +# +# Uncomment the following line to disable user-space updates +#-Dnouserdefaultappdir=true +EOM +) +fi + +# -Dsetuserappdirpath +if [ -z "${USERAPPDIRTEMPLATE}" ]; then + VMOPTIONS_USERAPPDIRPATH=$( cat << EOM +# +# Uncomment the below line to set a custom path for user-space updates -- use with caution. +# A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username. +# If not set, the default is ~/Library/Application Support/Jalview-Desktop for macOS +#-Dsetuserappdirpath=/tmp/jalview/%u +EOM +) +else + VMOPTIONS_USERAPPDIRPATH=$( cat << EOM +# +# The below line sets a custom path for user-space updates -- use with caution. +# A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username. +# If unset, the default is ~/Library/Application Support/Jalview-Desktop for macOS +-Dsetuserappdirpath=${USERAPPDIRTEMPLATE} +EOM +) +fi + +# -Dsilent=noupdate +if [ "${DISABLEALLUPDATES}" = 1 ]; then + VMOPTIONS_UPDATES=$( cat << EOM +# +# Comment out the following line to enable updates +-Dsilent=noupdate +EOM +) +else + VMOPTIONS_UPDATES=$( cat << EOM +# +# Uncomment the following line to also disable all updates +#-Dsilent=noupdate +EOM +) +fi + +printf "%s\n%s\n%s\n%s\n" "${VMOPTIONS_COMMENT}" "${VMOPTIONS_USERAPPDIR}" "${VMOPTIONS_USERAPPDIRPATH}" "${VMOPTIONS_UPDATES}" >> "${VMOPTIONS}" || addwarning "Possible problem adding options to '${VMOPTIONS}'" 14 + +# set a global path in /etc/paths.d +if [ "${DISABLEGLOBALPATH}" != 1 ]; then + LONGHASH=$( printf %s "${APPLICATIONFOLDER}/${APPNAME}/Contents/Resources/app" | shasum -a 256 -b ) + HASH=${LONGHASH:0:8} + NAME=${APPNAME%.app} + US_NAME=${APPNAME// /_} + PATHFILE="/etc/paths.d/${US_NAME}-${HASH}" + echo "${APPLICATIONFOLDER}/${APPNAME}/Contents/MacOS" > "${PATHFILE}" || addwarning "Possible problem writing path file '${PATHFILE}'" 15 +fi + +# show accumulated warnings +if [ "${#WARNINGS[@]}" != 0 ]; then + echo "-----------------" + echo "Installation complete." + echo "Warnings summary:" + printf -- '- %s\n' "${WARNINGS[@]}" +else + echo "Successful installation!" +fi + +exit $EXIT -- 1.7.10.2