#!/usr/bin/env zsh -f # Purpose: version 4 # # From: Timothy J. Luoma # Mail: luomat at gmail dot com # Date: 2021-09-20 autoload is-at-least NAME="$0:t:r" [[ -e "$HOME/.path" ]] && source "$HOME/.path" [[ -e "$HOME/.config/di/defaults.sh" ]] && source "$HOME/.config/di/defaults.sh" INSTALL_TO="${INSTALL_DIR_ALTERNATE-/Applications}/Bartender 4.app" XML_FEED='https://www.macbartender.com/B2/updates/updatesB4.php' # replace newlines, spaces, tabs, with one space # replace everything up to # replace everything after # replace the space in "> <" with a new line # replace all spaces with newlines # replace sparkle into with 'this'="foo" instead of foo # sort lines to get consistent output order # egrep to get just the lines we want # use awk to get just the values and not the fields INFO=($(curl -sfLS "$XML_FEED" \ | tr -s '\012| |\t' ' ' \ | sed -e 's#.*##g' \ -e 's#.*##g' \ -e 's#> <#>\ <#g' -e 's# #\ #g' -e 's##sparkle:minimumSystemVersion="#g' \ -e 's##"#g' \ -e 's##sparkle:releaseNotesLink="#g' \ -e 's##"#g' \ | sort \ | egrep 'sparkle:version|sparkle:shortVersionString|sparkle:releaseNotesLink|sparkle:minimumSystemVersion|url' \ | awk -F'"' '{print $2}' )) MIN_VERSION="$INFO[1]" RELEASE_NOTES_URL="$INFO[2]" LATEST_VERSION="$INFO[3]" LATEST_BUILD="$INFO[4]" URL="$INFO[5]" # If any of these are blank, we cannot continue if [ "$INFO" = "" -o "$URL" = "" -o "$LATEST_VERSION" = "" -o "$LATEST_BUILD" = "" ] then echo "$NAME: Error: bad data received: INFO: $INFO LATEST_VERSION: $LATEST_VERSION LATEST_BUILD: $LATEST_BUILD URL: $URL " >>/dev/stderr exit 1 fi ACTUAL_VERSION=$(sw_vers -productVersion) is-at-least "$MIN_VERSION" "$ACTUAL_VERSION" EXIT="$?" if [[ "$EXIT" == "1" ]] then echo "$NAME: '$INSTALL_TO:t' requires '$MIN_VERSION' to install but you are running '$ACTUAL_VERSION'." >>/dev/stderr exit 2 fi if [[ -e "$INSTALL_TO" ]] then INSTALLED_VERSION=$(defaults read "${INSTALL_TO}/Contents/Info" CFBundleShortVersionString) INSTALLED_BUILD=$(defaults read "${INSTALL_TO}/Contents/Info" CFBundleVersion) autoload is-at-least is-at-least "$LATEST_VERSION" "$INSTALLED_VERSION" VERSION_COMPARE="$?" is-at-least "$LATEST_BUILD" "$INSTALLED_BUILD" BUILD_COMPARE="$?" if [ "$VERSION_COMPARE" = "0" -a "$BUILD_COMPARE" = "0" ] then echo "$NAME: Up-To-Date ($INSTALLED_VERSION/$INSTALLED_BUILD)" exit 0 fi echo "$NAME: Outdated: $INSTALLED_VERSION/$INSTALLED_BUILD vs $LATEST_VERSION/$LATEST_BUILD" FIRST_INSTALL='no' if [[ ! -w "$INSTALL_TO" ]] then echo "$NAME: '$INSTALL_TO' exists, but you do not have 'write' access to it, therefore you cannot update it." >>/dev/stderr exit 2 fi else FIRST_INSTALL='yes' fi FILENAME="${DOWNLOAD_DIR_ALTERNATE-$HOME/Downloads}/Bartender-${${LATEST_VERSION}// /}_${${LATEST_BUILD}// /}.zip" RELEASE_NOTES_TXT="$FILENAME:r.txt" if [[ -e "$RELEASE_NOTES_TXT" ]] then cat "$RELEASE_NOTES_TXT" else if (( $+commands[html2text.py] )) then # html2text.py will give us something like markdown # uniq will make sure we don't have more than one blank line in a row RELEASE_NOTES=$(curl -sfLS "$RELEASE_NOTES_URL" | html2text.py | uniq) echo "${RELEASE_NOTES}\n\nSource: ${RELEASE_NOTES_URL}\nVersion: ${LATEST_VERSION} / ${LATEST_BUILD}\nURL: ${URL}" | tee "$RELEASE_NOTES_TXT" fi fi echo "$NAME: Downloading '$URL' to '$FILENAME':" curl --continue-at - --fail --location --output "$FILENAME" "$URL" EXIT="$?" ## exit 22 means 'the file was already fully downloaded' [ "$EXIT" != "0" -a "$EXIT" != "22" ] && echo "$NAME: Download of $URL failed (EXIT = $EXIT)" && exit 0 [[ ! -e "$FILENAME" ]] && echo "$NAME: $FILENAME does not exist." && exit 0 [[ ! -s "$FILENAME" ]] && echo "$NAME: $FILENAME is zero bytes." && rm -f "$FILENAME" && exit 0 egrep -q '^Local sha256:$' "$FILENAME:r.txt" 2>/dev/null EXIT="$?" if [ "$EXIT" = "1" -o ! -e "$FILENAME:r.txt" ] then (cd "$FILENAME:h" ; \ echo "\n\nLocal sha256:" ; \ shasum -a 256 "$FILENAME:t" \ ) >>| "$FILENAME:r.txt" fi TEMPDIR=$(mktemp -d "${TMPDIR-/tmp/}${NAME-$0:r}-XXXXXXXX") ## make sure that the .zip is valid before we proceed (command unzip -l "$FILENAME" 2>&1 )>/dev/null EXIT="$?" if [ "$EXIT" = "0" ] then echo "$NAME: '$FILENAME' is a valid zip file." else echo "$NAME: '$FILENAME' is an invalid zip file (\$EXIT = $EXIT)" mv -fv "$FILENAME" "$TEMPDIR/" mv -fv "$FILENAME:r".* "$TEMPDIR/" exit 0 fi ## unzip to a temporary directory UNZIP_TO=$(mktemp -d "${TEMPDIR}/${NAME}-XXXXXXXX") echo "$NAME: Unzipping '$FILENAME' to '$UNZIP_TO':" ditto -xk --noqtn "$FILENAME" "$UNZIP_TO" EXIT="$?" if [[ "$EXIT" == "0" ]] then echo "$NAME: Unzip successful" else # failed echo "$NAME failed (ditto -xkv '$FILENAME' '$UNZIP_TO')" exit 1 fi if [[ -e "$INSTALL_TO" ]] then pgrep -xq "$INSTALL_TO:t:r" \ && LAUNCH='yes' \ && osascript -e "tell application \"$INSTALL_TO:t:r\" to quit" echo "$NAME: Moving existing (old) '$INSTALL_TO' to '$TEMPDIR/'." mv -f "$INSTALL_TO" "$TEMPDIR/$INSTALL_TO:t:r.$INSTALLED_VERSION.app" EXIT="$?" if [[ "$EXIT" != "0" ]] then echo "$NAME: failed to move existing '$INSTALL_TO' to '$TEMPDIR'." exit 1 fi fi echo "$NAME: Moving new version of '$INSTALL_TO:t' (from '$UNZIP_TO') to '$INSTALL_TO'." # Move the file out of the folder mv -n "$UNZIP_TO/$INSTALL_TO:t" "$INSTALL_TO" EXIT="$?" if [[ "$EXIT" = "0" ]] then echo "$NAME: Successfully installed '$UNZIP_TO/$INSTALL_TO:t' to '$INSTALL_TO'." else echo "$NAME: Failed to move '$UNZIP_TO/$INSTALL_TO:t' to '$INSTALL_TO'." exit 1 fi [[ "$LAUNCH" = "yes" ]] && open "$INSTALL_TO" exit 0 #EOF