summaryrefslogtreecommitdiff
path: root/tools/check_for_upgrade.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tools/check_for_upgrade.sh')
-rw-r--r--tools/check_for_upgrade.sh183
1 files changed, 137 insertions, 46 deletions
diff --git a/tools/check_for_upgrade.sh b/tools/check_for_upgrade.sh
index c8dedcf77..157b0cce2 100644
--- a/tools/check_for_upgrade.sh
+++ b/tools/check_for_upgrade.sh
@@ -1,62 +1,153 @@
-#!/usr/bin/env zsh
+# Migrate .zsh-update file to $ZSH_CACHE_DIR
+if [[ -f ~/.zsh-update && ! -f "${ZSH_CACHE_DIR}/.zsh-update" ]]; then
+ mv ~/.zsh-update "${ZSH_CACHE_DIR}/.zsh-update"
+fi
-zmodload zsh/datetime
+# Get user's update preferences
+#
+# Supported update modes:
+# - prompt (default): the user is asked before updating when it's time to update
+# - auto: the update is performed automatically when it's time
+# - reminder: a reminder is shown to the user when it's time to update
+# - disabled: automatic update is turned off
+zstyle -s ':omz:update' mode update_mode || update_mode=prompt
-function _current_epoch() {
- echo $(( $EPOCHSECONDS / 60 / 60 / 24 ))
-}
+# Support old-style settings
+[[ "$DISABLE_UPDATE_PROMPT" != true ]] || update_mode=auto
+[[ "$DISABLE_AUTO_UPDATE" != true ]] || update_mode=disabled
+
+# Cancel update if:
+# - the automatic update is disabled.
+# - the current user doesn't have write permissions nor owns the $ZSH directory.
+# - git is unavailable on the system.
+if [[ "$update_mode" = disabled ]] \
+ || [[ ! -w "$ZSH" || ! -O "$ZSH" ]] \
+ || ! command -v git &>/dev/null; then
+ unset update_mode
+ return
+fi
-function _update_zsh_update() {
- echo "LAST_EPOCH=$(_current_epoch)" >! ${ZSH_CACHE_DIR}/.zsh-update
+function current_epoch() {
+ zmodload zsh/datetime
+ echo $(( EPOCHSECONDS / 60 / 60 / 24 ))
}
-function _upgrade_zsh() {
- env ZSH=$ZSH sh $ZSH/tools/upgrade.sh
- # update the zsh file
- _update_zsh_update
+function is_update_available() {
+ local branch
+ branch=${"$(git -C "$ZSH" config --local oh-my-zsh.branch)":-master}
+
+ local remote remote_url remote_repo
+ remote=${"$(git -C "$ZSH" config --local oh-my-zsh.remote)":-origin}
+ remote_url=$(git -C "$ZSH" config remote.$remote.url)
+
+ local repo
+ case "$remote_url" in
+ https://github.com/*) repo=${${remote_url#https://github.com/}%.git} ;;
+ git@github.com:*) repo=${${remote_url#git@github.com:}%.git} ;;
+ *)
+ # If the remote is not using GitHub we can't check for updates
+ # Let's assume there are updates
+ return 0 ;;
+ esac
+
+ # If the remote repo is not the official one, let's assume there are updates available
+ [[ "$repo" = ohmyzsh/ohmyzsh ]] || return 0
+ local api_url="https://api.github.com/repos/${repo}/commits/${branch}"
+
+ # Get local and remote HEADs and compare them. If we can't get either assume there are updates
+ local local_head remote_head
+ local_head=$(git -C "$ZSH" rev-parse $branch 2>/dev/null) || return 0
+
+ remote_head=$(curl -fsSL -H 'Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null) \
+ || remote_head=$(wget -O- --header='Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null) \
+ || remote_head=$(HTTP_ACCEPT='Accept: application/vnd.github.v3.sha' fetch -o - $api_url 2>/dev/null) \
+ || return 0
+
+ # Compare local and remote HEADs
+ [[ "$local_head" != "$remote_head" ]]
}
-epoch_target=$UPDATE_ZSH_DAYS
-if [[ -z "$epoch_target" ]]; then
- # Default to old behavior
- epoch_target=13
-fi
+function update_last_updated_file() {
+ echo "LAST_EPOCH=$(current_epoch)" >! "${ZSH_CACHE_DIR}/.zsh-update"
+}
-# Cancel upgrade if the current user doesn't have write permissions for the
-# oh-my-zsh directory.
-[[ -w "$ZSH" ]] || return 0
+function update_ohmyzsh() {
+ if ZSH="$ZSH" zsh -f "$ZSH/tools/upgrade.sh" --interactive; then
+ update_last_updated_file
+ fi
+}
-# Cancel upgrade if git is unavailable on the system
-whence git >/dev/null || return 0
+() {
+ emulate -L zsh
-if mkdir "$ZSH/log/update.lock" 2>/dev/null; then
- if [ -f ${ZSH_CACHE_DIR}/.zsh-update ]; then
- . ${ZSH_CACHE_DIR}/.zsh-update
+ local epoch_target mtime option LAST_EPOCH
- if [[ -z "$LAST_EPOCH" ]]; then
- _update_zsh_update
- rmdir $ZSH/log/update.lock # TODO: fix later
- return 0
+ # Remove lock directory if older than a day
+ zmodload zsh/datetime
+ zmodload -F zsh/stat b:zstat
+ if mtime=$(zstat +mtime "$ZSH/log/update.lock" 2>/dev/null); then
+ if (( (mtime + 3600 * 24) < EPOCHSECONDS )); then
+ command rm -rf "$ZSH/log/update.lock"
fi
+ fi
- epoch_diff=$(($(_current_epoch) - $LAST_EPOCH))
- if [ $epoch_diff -gt $epoch_target ]; then
- if [ "$DISABLE_UPDATE_PROMPT" = "true" ]; then
- _upgrade_zsh
- else
- echo "[Oh My Zsh] Would you like to update? [Y/n]: \c"
- read line
- if [[ "$line" == Y* ]] || [[ "$line" == y* ]] || [ -z "$line" ]; then
- _upgrade_zsh
- else
- _update_zsh_update
- fi
- fi
- fi
+ # Check for lock directory
+ if ! command mkdir "$ZSH/log/update.lock" 2>/dev/null; then
+ return
+ fi
+
+ # Remove lock directory on exit. `return $ret` is important for when trapping a SIGINT:
+ # The return status from the function is handled specially. If it is zero, the signal is
+ # assumed to have been handled, and execution continues normally. Otherwise, the shell
+ # will behave as interrupted except that the return status of the trap is retained.
+ # This means that for a CTRL+C, the trap needs to return the same exit status so that
+ # the shell actually exits what it's running.
+ trap "
+ ret=\$?
+ unset update_mode
+ unset -f current_epoch is_update_available update_last_updated_file update_ohmyzsh 2>/dev/null
+ command rm -rf '$ZSH/log/update.lock'
+ return \$ret
+ " EXIT INT QUIT
+
+ # Create or update .zsh-update file if missing or malformed
+ if ! source "${ZSH_CACHE_DIR}/.zsh-update" 2>/dev/null || [[ -z "$LAST_EPOCH" ]]; then
+ update_last_updated_file
+ return
+ fi
+
+ # Number of days before trying to update again
+ zstyle -s ':omz:update' frequency epoch_target || epoch_target=${UPDATE_ZSH_DAYS:-13}
+ # Test if enough time has passed until the next update
+ if (( ( $(current_epoch) - $LAST_EPOCH ) < $epoch_target )); then
+ return
+ fi
+
+ # Check if there are updates available before proceeding
+ if ! is_update_available; then
+ return
+ fi
+
+ # Ask for confirmation before updating unless in auto mode
+ if [[ "$update_mode" = auto ]]; then
+ update_ohmyzsh
+ elif [[ "$update_mode" = reminder ]]; then
+ echo "[oh-my-zsh] It's time to update! You can do that by running \`omz update\`"
else
- # create the zsh file
- _update_zsh_update
+ # input sink to swallow all characters typed before the prompt
+ # and add a newline if there wasn't one after characters typed
+ while read -t -k 1 option; do true; done
+ [[ "$option" != ($'\n'|"") ]] && echo
+
+ echo -n "[oh-my-zsh] Would you like to update? [Y/n] "
+ read -r -k 1 option
+ [[ "$option" != $'\n' ]] && echo
+ case "$option" in
+ [yY$'\n']) update_ohmyzsh ;;
+ [nN]) update_last_updated_file ;;
+ esac
fi
+}
- rmdir $ZSH/log/update.lock
-fi
+unset update_mode
+unset -f current_epoch is_update_available update_last_updated_file update_ohmyzsh