Update Cursor version resolution to avoid latest lagging behind newly published patch releases.
This commit is contained in:
@@ -95,6 +95,25 @@ The `update-cursor.sh` script provides:
|
|||||||
- **x86_64 AppImage Download**: `https://api2.cursor.sh/updates/download/golden/linux-x64/cursor/{version}`
|
- **x86_64 AppImage Download**: `https://api2.cursor.sh/updates/download/golden/linux-x64/cursor/{version}`
|
||||||
- **aarch64 AppImage Download**: `https://api2.cursor.sh/updates/download/golden/linux-arm64/cursor/{version}`
|
- **aarch64 AppImage Download**: `https://api2.cursor.sh/updates/download/golden/linux-arm64/cursor/{version}`
|
||||||
|
|
||||||
|
### Version pointers / "channels"
|
||||||
|
|
||||||
|
Cursor exposes a few redirect-style pointers that may not always move in lockstep:
|
||||||
|
|
||||||
|
- **`.../cursor/latest`**: “promoted” latest build for that channel. This can lag a new release during phased rollout / promotion.
|
||||||
|
- **`.../cursor/{major.minor}` (e.g. `.../cursor/2.2`)**: latest patch within that major.minor line. This can point to a newer build earlier than `latest`.
|
||||||
|
|
||||||
|
Concrete example (this has happened in practice):
|
||||||
|
|
||||||
|
- `.../cursor/latest` redirects to **`Cursor-2.2.43-...AppImage`**
|
||||||
|
- `.../cursor/2.2` redirects to **`Cursor-2.2.44-...AppImage`**
|
||||||
|
|
||||||
|
In that situation, **`latest` is behind**. This flake’s updater checks both and will choose **2.2.44**.
|
||||||
|
|
||||||
|
This flake’s `update-cursor.sh` default (**auto**) strategy:
|
||||||
|
|
||||||
|
- **Checks multiple pointers**: `latest`, the current installed major.minor (e.g. `2.2`), and (if different) `latest`’s own major.minor (e.g. `2.3`).
|
||||||
|
- **Picks the highest semver**: so it won’t stick to an old minor, but it also won’t miss patch releases when `latest` lags.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+80
-11
@@ -3,7 +3,11 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Script to manually update Cursor version/hashes used by the flake
|
# Script to manually update Cursor version/hashes used by the flake
|
||||||
# Usage: ./update-cursor.sh [version]
|
# Usage:
|
||||||
|
# ./update-cursor.sh # auto: pick highest of ("latest" pointer, current major.minor pointer)
|
||||||
|
# ./update-cursor.sh 2.2.44 # pin exact version
|
||||||
|
# ./update-cursor.sh latest # follow the "latest" pointer only
|
||||||
|
# ./update-cursor.sh 2.2 # follow a major.minor pointer only
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
RELEASE_FILE="$SCRIPT_DIR/cursor-release.nix"
|
RELEASE_FILE="$SCRIPT_DIR/cursor-release.nix"
|
||||||
@@ -11,26 +15,63 @@ RELEASE_FILE="$SCRIPT_DIR/cursor-release.nix"
|
|||||||
CHANNEL_FOR_SYSTEM_x86_64_linux="linux-x64"
|
CHANNEL_FOR_SYSTEM_x86_64_linux="linux-x64"
|
||||||
CHANNEL_FOR_SYSTEM_aarch64_linux="linux-arm64"
|
CHANNEL_FOR_SYSTEM_aarch64_linux="linux-arm64"
|
||||||
|
|
||||||
# Function to get latest version from API redirect
|
# Get a redirect URL for a given "track" pointer (e.g. latest, 2.2).
|
||||||
|
get_redirect_url() {
|
||||||
|
local track="${1:?track is required}"
|
||||||
|
local url="https://api2.cursor.sh/updates/download/golden/linux-x64/cursor/${track}"
|
||||||
|
|
||||||
|
# Avoid stale CDN/proxy cache results for fast-moving pointers like "latest".
|
||||||
|
curl -sS -I \
|
||||||
|
-H 'Cache-Control: no-cache' \
|
||||||
|
-H 'Pragma: no-cache' \
|
||||||
|
"$url" \
|
||||||
|
| awk 'BEGIN{IGNORECASE=1} $1=="location:" {print $2; exit}' \
|
||||||
|
| tr -d '\r\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve a track pointer (e.g. latest, 2.2) into an actual semver (e.g. 2.2.44).
|
||||||
get_latest_version() {
|
get_latest_version() {
|
||||||
# Get the redirect URL and extract version from the AppImage filename
|
local track="${1:-latest}"
|
||||||
|
|
||||||
local redirect_url
|
local redirect_url
|
||||||
redirect_url=$(curl -s -I "https://api2.cursor.sh/updates/download/golden/linux-x64/cursor/latest" | grep -i location | cut -d' ' -f2 | tr -d '\r\n')
|
redirect_url="$(get_redirect_url "$track")"
|
||||||
|
|
||||||
if [[ -n "$redirect_url" ]]; then
|
if [[ -n "$redirect_url" ]]; then
|
||||||
# Extract version from URL like: .../Cursor-1.7.39-x86_64.AppImage
|
# Extract version from URL like: .../Cursor-2.2.44-x86_64.AppImage
|
||||||
echo "$redirect_url" | grep -o 'Cursor-[0-9]\+\.[0-9]\+\.[0-9]\+' | sed 's/Cursor-//'
|
echo "$redirect_url" | grep -Eo 'Cursor-[0-9]+\.[0-9]+\.[0-9]+' | sed 's/Cursor-//'
|
||||||
else
|
else
|
||||||
echo "Error: Could not get redirect URL"
|
echo "Error: Could not get redirect URL for track: $track" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# True if arg looks like a full semver (e.g. 2.2.44).
|
||||||
|
is_full_semver() {
|
||||||
|
[[ "${1:-}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# True if arg looks like a pointer we can resolve (e.g. latest, 2.2).
|
||||||
|
is_pointer() {
|
||||||
|
[[ "${1:-}" == "latest" || "${1:-}" =~ ^[0-9]+\.[0-9]+$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
# Function to get current version from cursor-release.nix
|
# Function to get current version from cursor-release.nix
|
||||||
get_current_version() {
|
get_current_version() {
|
||||||
grep -o 'version = "[^"]*"' "$RELEASE_FILE" | head -1 | cut -d'"' -f2
|
grep -o 'version = "[^"]*"' "$RELEASE_FILE" | head -1 | cut -d'"' -f2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Derive major.minor track from a full version (e.g. 2.2.43 -> 2.2).
|
||||||
|
get_track_from_version() {
|
||||||
|
local version="${1:?version is required}"
|
||||||
|
echo "$version" | awk -F. '{print $1 "." $2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return the highest of the provided dotted versions using natural version sort.
|
||||||
|
semver_max() {
|
||||||
|
# Accepts N args; prints the max.
|
||||||
|
printf '%s\n' "$@" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n1
|
||||||
|
}
|
||||||
|
|
||||||
# Function to compute sha256 for a given system+version
|
# Function to compute sha256 for a given system+version
|
||||||
prefetch_sha256() {
|
prefetch_sha256() {
|
||||||
local system="$1"
|
local system="$1"
|
||||||
@@ -126,11 +167,39 @@ main() {
|
|||||||
|
|
||||||
# Determine target version
|
# Determine target version
|
||||||
if [[ -n "$target_version" ]]; then
|
if [[ -n "$target_version" ]]; then
|
||||||
echo "Target version: $target_version"
|
if is_full_semver "$target_version"; then
|
||||||
|
echo "Target version (pinned): $target_version"
|
||||||
|
elif is_pointer "$target_version"; then
|
||||||
|
echo "Target pointer: $target_version"
|
||||||
|
target_version="$(get_latest_version "$target_version")"
|
||||||
|
echo "Resolved version: $target_version"
|
||||||
else
|
else
|
||||||
echo "Fetching latest version..."
|
echo "Error: Invalid argument: $target_version" >&2
|
||||||
target_version=$(get_latest_version)
|
echo "Expected: full version (e.g. 2.2.44) or pointer (latest or 2.2)" >&2
|
||||||
echo "Latest version: $target_version"
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Auto mode:
|
||||||
|
# - Check "latest" to allow moving to new major/minor (e.g. 2.3.x)
|
||||||
|
# - Check current major.minor line to avoid missing patches when "latest" lags (e.g. 2.2.44 vs latest=2.2.43)
|
||||||
|
# - Also check latest's own major.minor line (if latest=2.3.0 but 2.3 pointer is 2.3.1)
|
||||||
|
local current_track v_latest latest_track v_latest_track v_current_track
|
||||||
|
current_track="$(get_track_from_version "$current_version")"
|
||||||
|
|
||||||
|
echo "Fetching pointers: latest, $current_track"
|
||||||
|
v_latest="$(get_latest_version latest)"
|
||||||
|
latest_track="$(get_track_from_version "$v_latest")"
|
||||||
|
v_current_track="$(get_latest_version "$current_track")"
|
||||||
|
|
||||||
|
if [[ "$latest_track" != "$current_track" ]]; then
|
||||||
|
echo "Latest is on a different minor: $latest_track (also checking it)"
|
||||||
|
v_latest_track="$(get_latest_version "$latest_track")"
|
||||||
|
else
|
||||||
|
v_latest_track="$v_latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
target_version="$(semver_max "$v_latest" "$v_current_track" "$v_latest_track")"
|
||||||
|
echo "Resolved: latest=$v_latest pointer($current_track)=$v_current_track pointer($latest_track)=$v_latest_track -> chosen=$target_version"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if update is needed
|
# Check if update is needed
|
||||||
|
|||||||
Reference in New Issue
Block a user