Last active
June 27, 2026 12:15
-
-
Save knu/86c3d1a2c4cbcf02b1d6306fdffd8ded to your computer and use it in GitHub Desktop.
Zero-downtime mise upgrade
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| set -e | |
| config=$HOME/.config/mise/config.toml | |
| usage() { | |
| echo "Usage: $0 [-p config] [tool...]" | |
| } | |
| current_tools() { | |
| printf %s "$outdated" | jq -r \ | |
| 'to_entries[] | select(.value.current != null) | "\(.key)@\(.value.current)"' | |
| } | |
| latest_tools() { | |
| printf %s "$outdated" | jq -r \ | |
| 'to_entries[] | "\(.key)@\(.value.latest)"' | |
| } | |
| new_latest_tools() { | |
| latest_tools | while IFS= read -r spec; do | |
| tool=${spec%@*} | |
| version=${spec##*@} | |
| if ! mise ls --json --installed "$tool" | | |
| jq -e --arg version "$version" 'any(.[]; .version == $version)' >/dev/null; then | |
| printf '%s\n' "$spec" | |
| fi | |
| done | |
| } | |
| pin_current_paths() { | |
| [ -n "$current_specs" ] || return 0 | |
| # shellcheck disable=SC2016,SC2086 | |
| PATH=$(mise exec $current_specs -- sh -c 'printf %s "$PATH"') | |
| export PATH | |
| } | |
| cleanup_new_latest_tools() { | |
| [ -n "$new_latest_specs" ] || return 0 | |
| # shellcheck disable=SC2086 | |
| mise uninstall -y $new_latest_specs | |
| } | |
| while getopts "p:" opt; do | |
| case $opt in | |
| p) | |
| config=$OPTARG | |
| ;; | |
| \?) | |
| usage | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| config=$(realpath "$config") | |
| config_bak=${config%.toml}.bak.toml | |
| if [ -f "$config_bak" ]; then | |
| echo "$config_bak exists; upgrade seems to be in progress." | |
| exit 1 | |
| fi | |
| cd "$(dirname "$config")" | |
| # Get outdated tools. | |
| outdated=$(mise outdated --json "$@") | |
| if [ "$outdated" = '{}' ]; then | |
| echo Nothing to upgrade. | |
| exit | |
| fi | |
| current_specs=$(current_tools) | |
| latest_specs=$(latest_tools) | |
| # Prefer currently installed tool bins while new versions are being installed. | |
| pin_current_paths | |
| new_latest_specs=$(new_latest_tools) | |
| # Pin the tools to the currently installed versions while new versions are being installed. | |
| cp -p "$config" "$config_bak" | |
| if [ -n "$current_specs" ]; then | |
| # shellcheck disable=SC2086 | |
| mise use --path "$config" $current_specs | |
| fi | |
| # Install the latest versions. If this fails, remove any partial latest | |
| # installs before restoring the config. | |
| # shellcheck disable=SC2086 | |
| if mise install $latest_specs; then | |
| mv "$config_bak" "$config" | |
| else | |
| ret=$? | |
| if cleanup_new_latest_tools; then | |
| mv "$config_bak" "$config" | |
| else | |
| echo "Upgrade cleanup failed; $config remains pinned to the previous versions." >&2 | |
| fi | |
| exit "$ret" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment