@@ -146,13 +146,72 @@ install_uncloud_binaries() {
146146 esac
147147
148148 local uncloudd_install_path=" ${INSTALL_BIN_DIR} /uncloudd"
149+ local installed_version=" "
149150 if [ -f " ${uncloudd_install_path} " ]; then
150- # TODO: Check the version of the installed uncloudd binary and update if there is a newer stable version.
151- log " ✓ uncloudd binary is already installed."
152- return
151+ installed_version=$( " ${uncloudd_install_path} " version -o ' {{.Version}}' 2> /dev/null || true)
153152 fi
154153
155- log " ⏳ Installing Uncloud binaries..."
154+ # Decide whether to (re)install based on UNCLOUD_VERSION and the already installed binary, and pick the
155+ # download URL for the same channel/tag.
156+ local uncloudd_url uninstall_ref
157+ local uncloudd_archive_name=" uncloudd_linux_${file_arch} .tar.gz"
158+
159+ case " ${UNCLOUD_VERSION} " in
160+ nightly)
161+ log " ⏳ Installing uncloudd from the nightly channel (installed: ${installed_version:- none} )..."
162+ uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/download/nightly/${uncloudd_archive_name} "
163+ # The 'nightly' tag is deleted and recreated on every nightly build, so pin uninstall.sh to main
164+ # to avoid racing.
165+ uninstall_ref=" refs/heads/main"
166+ ;;
167+ latest)
168+ # Resolve the redirect of releases/latest to discover the concrete latest version.
169+ local latest_url latest_version
170+ latest_url=$( curl -sLI -o /dev/null -w ' %{url_effective}' \
171+ " ${UNCLOUD_GITHUB_URL} /releases/latest" 2> /dev/null || true)
172+ latest_version=" ${latest_url##*/ } "
173+ latest_version=" ${latest_version# v} "
174+
175+ uninstall_ref=" refs/tags/v${latest_version} "
176+
177+ if [ -z " ${latest_version} " ] || [ " ${latest_version} " = " latest" ]; then
178+ warning " Could not resolve the version of the latest release on GitHub."
179+ # Fall back to the redirecting URL so curl follows whatever GitHub considers latest.
180+ uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/latest/download/${uncloudd_archive_name} "
181+ uninstall_ref=" refs/heads/main"
182+ elif [ -z " ${installed_version} " ]; then
183+ log " ⏳ Installing uncloudd ${latest_version} (latest stable)..."
184+ uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/download/v${latest_version} /${uncloudd_archive_name} "
185+ elif [ " ${installed_version} " = " ${latest_version} " ]; then
186+ log " ✓ uncloudd ${installed_version} is already the latest stable version."
187+ return 0
188+ else
189+ # Substitute '-' with '~' so sort -V treats pre-release versions per SemVer (Debian-style rules):
190+ # 0.20.0~nightly-abc < 0.20.0 < 0.21.0~nightly-def.
191+ # latest_version is always a clean stable tag from releases/latest, so the substitution is one-sided.
192+ local newest
193+ newest=$( printf ' %s\n%s\n' " ${installed_version// -/ ~} " " ${latest_version} " | sort -V | tail -n1)
194+ if [ " ${newest} " = " ${latest_version} " ]; then
195+ log " ⏳ Upgrading uncloudd ${installed_version} → ${latest_version} ..."
196+ uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/download/v${latest_version} /${uncloudd_archive_name} "
197+ else
198+ log " ✓ uncloudd ${installed_version} is newer than the latest stable ${latest_version} , keeping it."
199+ return 0
200+ fi
201+ fi
202+ ;;
203+ * )
204+ # Explicit version. Install if it differs from the installed one (covers upgrade and downgrade).
205+ if [ " ${installed_version} " = " ${UNCLOUD_VERSION} " ]; then
206+ log " ✓ uncloudd ${installed_version} matches the requested version, keeping it."
207+ return 0
208+ fi
209+ log " ⏳ Installing uncloudd ${UNCLOUD_VERSION} (replacing ${installed_version:- none} )..."
210+ uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/download/v${UNCLOUD_VERSION} /${uncloudd_archive_name} "
211+ uninstall_ref=" refs/tags/v${UNCLOUD_VERSION} "
212+ ;;
213+ esac
214+ local uninstall_url=" https://raw.githubusercontent.com/psviderski/uncloud/${uninstall_ref} /scripts/uninstall.sh"
156215
157216 # Create a temporary directory for downloads.
158217 local tmp_dir
@@ -161,18 +220,6 @@ install_uncloud_binaries() {
161220 # shellcheck disable=SC2064
162221 trap " rm -rf '$tmp_dir '" EXIT
163222
164- local uncloudd_url
165- local uninstall_url
166- if [ " ${UNCLOUD_VERSION} " == " latest" ]; then
167- uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/latest/download/uncloudd_linux_${file_arch} .tar.gz"
168- uninstall_url=" https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/uninstall.sh"
169- elif [ " ${UNCLOUD_VERSION} " == " nightly" ]; then
170- uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/download/nightly/uncloudd_linux_${file_arch} .tar.gz"
171- uninstall_url=" https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/uninstall.sh"
172- else
173- uncloudd_url=" ${UNCLOUD_GITHUB_URL} /releases/download/v${UNCLOUD_VERSION} /uncloudd_linux_${file_arch} .tar.gz"
174- uninstall_url=" https://raw.githubusercontent.com/psviderski/uncloud/refs/tags/v${UNCLOUD_VERSION} /scripts/uninstall.sh"
175- fi
176223 local uncloudd_download_path=" ${tmp_dir} /uncloudd.tar.gz"
177224 local uninstall_download_path=" ${tmp_dir} /uninstall.sh"
178225
0 commit comments