|
#!/bin/bash |
|
|
|
set -e |
|
|
|
PKG="lm-studio" |
|
URL="https://lmstudio.ai/download/latest/linux/x64?format=deb" |
|
UA="Mozilla/5.0" |
|
TMP_DEB="/tmp/lmstudio_latest.deb" |
|
TMP_HEAD="$(mktemp --suffix=.deb)" |
|
trap 'rm -f "$TMP_HEAD" "$TMP_DEB"' EXIT |
|
|
|
# LM Studio ships its launcher icon under hicolor/0x0/apps -- an invalid size |
|
# bucket the icon theme ignores -- so the app installs with no icon, and every |
|
# release so far packages it the same way. Mirror the package's icon into a |
|
# valid per-user bucket and refresh the cache. Kept under ~/.local so apt |
|
# upgrades never clobber it; re-copied only when missing or when it changed. |
|
ensure_icon() { |
|
local pkg_icon="/usr/share/icons/hicolor/0x0/apps/lm-studio.png" |
|
local hicolor="$HOME/.local/share/icons/hicolor" |
|
local user_icon="$hicolor/512x512/apps/lm-studio.png" |
|
[ -f "$pkg_icon" ] || return 0 |
|
cmp -s "$pkg_icon" "$user_icon" && return 0 |
|
mkdir -p "$(dirname "$user_icon")" |
|
cp -f "$pkg_icon" "$user_icon" |
|
[ -f "$hicolor/index.theme" ] || cp /usr/share/icons/hicolor/index.theme "$hicolor/index.theme" 2>/dev/null || true |
|
gtk-update-icon-cache -f -q "$hicolor" 2>/dev/null || true |
|
echo "Refreshed LM Studio launcher icon -> $user_icon" |
|
} |
|
|
|
echo "Resolving latest LM Studio download URL..." |
|
deb_url=$(curl -fsSL -A "$UA" -o /dev/null -w '%{url_effective}' "$URL") || deb_url="" |
|
if [ -z "$deb_url" ]; then |
|
echo "Could not resolve the LM Studio download URL from $URL" >&2 |
|
exit 1 |
|
fi |
|
echo "Latest .deb: $deb_url" |
|
|
|
# The .deb is ~600 MB and the version in its filename (e.g. 0.4.14-4) is not the |
|
# string dpkg records (e.g. 0.4.14+4), so the two cannot be compared directly. |
|
# Read the real Version from the package's own control metadata, fetching only |
|
# the front of the file -- the small control.tar.* member precedes the large |
|
# data.tar.* -- so an up-to-date install is detected without downloading ~600 MB. |
|
echo "Reading candidate version from package metadata..." |
|
curl -fsSL -A "$UA" -r 0-2097151 "$deb_url" -o "$TMP_HEAD" |
|
control_member=$(ar t "$TMP_HEAD" 2>/dev/null | grep -m1 '^control\.tar' || true) |
|
if [ -z "$control_member" ]; then |
|
echo "Could not find the control member in the downloaded .deb header." >&2 |
|
exit 1 |
|
fi |
|
case "$control_member" in |
|
*.gz) decomp="gzip -dc" ;; |
|
*.xz) decomp="xz -dc" ;; |
|
*.zst) decomp="zstd -dc" ;; |
|
*.bz2) decomp="bzip2 -dc" ;; |
|
*) decomp="cat" ;; |
|
esac |
|
latest=$(ar p "$TMP_HEAD" "$control_member" 2>/dev/null | $decomp 2>/dev/null | tar -xO ./control 2>/dev/null | sed -n 's/^Version: *//p') || true |
|
if [ -z "$latest" ]; then |
|
echo "Could not read Version from the package control metadata." >&2 |
|
exit 1 |
|
fi |
|
|
|
installed=$(dpkg-query -W -f='${Version}' "$PKG" 2>/dev/null || echo "") |
|
|
|
if [ "$installed" = "$latest" ]; then |
|
echo "LM Studio is already up to date ($installed)." |
|
ensure_icon |
|
exit 0 |
|
fi |
|
|
|
echo "Updating LM Studio ${installed:-(none)} -> $latest" |
|
echo "Downloading $deb_url ..." |
|
curl -fL -A "$UA" "$deb_url" -o "$TMP_DEB" |
|
|
|
echo "Installing LM Studio..." |
|
sudo dpkg -i "$TMP_DEB" |
|
|
|
ensure_icon |
|
|
|
echo "LM Studio updated successfully to $latest!" |