JAL-3631 Comprehensive install shell script for macos
authorBen Soares <b.soares@dundee.ac.uk>
Thu, 25 Jul 2024 16:35:57 +0000 (17:35 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Thu, 25 Jul 2024 16:35:57 +0000 (17:35 +0100)
utils/install4j/macos-install-jalview.sh [new file with mode: 0755]

diff --git a/utils/install4j/macos-install-jalview.sh b/utils/install4j/macos-install-jalview.sh
new file mode 100755 (executable)
index 0000000..b91f9ca
--- /dev/null
@@ -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