|
#!/usr/bin/env python3 |
|
# -*- coding: utf-8 -*- |
|
|
|
import os |
|
import sys |
|
import json |
|
import hashlib |
|
import urllib.request |
|
import urllib.error |
|
|
|
# --- Configuration --- |
|
API_URL = "https://www.cursor.com/api/download?platform=linux-x64&releaseTrack=stable" |
|
ICON_URL = "https://avatars.githubusercontent.com/u/126759922?v=4" |
|
TARGET_DIR = "/opt/cursor" |
|
APPIMAGE_NAME = "cursor.AppImage" |
|
DESKTOP_FILE = "/usr/share/applications/cursor.desktop" |
|
ICON_NAME = "cursor.png" |
|
# ---------------------- |
|
|
|
def calculate_file_hash(path, algo="sha256"): |
|
h = hashlib.new(algo) |
|
with open(path, "rb") as f: |
|
while chunk := f.read(8192): |
|
h.update(chunk) |
|
return h.hexdigest() |
|
|
|
def download_file(url, dest, headers=None): |
|
req = urllib.request.Request(url, headers=headers or {}) |
|
with urllib.request.urlopen(req) as resp: |
|
total = int(resp.info().get("Content-Length", -1)) |
|
downloaded = 0 |
|
with open(dest, "wb") as out: |
|
while chunk := resp.read(8192): |
|
downloaded += len(chunk) |
|
out.write(chunk) |
|
if total > 0: |
|
print(f"\rDownloading… {downloaded*100/total:5.1f}%", end="", flush=True) |
|
print("\nDone") |
|
|
|
def fetch_download_url(): |
|
try: |
|
with urllib.request.urlopen(API_URL) as r: |
|
data = json.load(r) |
|
url = data.get("downloadUrl") |
|
if not url: |
|
print("API response missing downloadUrl:", data, file=sys.stderr) |
|
sys.exit(1) |
|
return url |
|
except (urllib.error.URLError, json.JSONDecodeError) as e: |
|
print("Failed to fetch download info:", e, file=sys.stderr) |
|
sys.exit(1) |
|
|
|
os.makedirs(TARGET_DIR, exist_ok=True) |
|
current_path = os.path.join(TARGET_DIR, APPIMAGE_NAME) |
|
|
|
if os.path.isfile(current_path): |
|
print("Checking for updates…") |
|
current_hash = calculate_file_hash(current_path) |
|
else: |
|
print("First-time install…") |
|
current_hash = None |
|
|
|
print("Retrieving latest Cursor download URL…") |
|
download_url = fetch_download_url() |
|
print("Download URL:", download_url) |
|
|
|
new_path = os.path.join(TARGET_DIR, "cursor_new.AppImage") |
|
download_file(download_url, new_path, headers={"User-Agent":"Mozilla/5.0"}) |
|
|
|
new_hash = calculate_file_hash(new_path) |
|
if new_hash == current_hash: |
|
print("Already up to date.") |
|
os.remove(new_path) |
|
sys.exit(0) |
|
|
|
print("Installing new version…") |
|
os.chmod(new_path, 0o755) |
|
if os.path.isfile(current_path): |
|
os.remove(current_path) |
|
os.rename(new_path, current_path) |
|
|
|
icon_path = os.path.join(TARGET_DIR, ICON_NAME) |
|
try: |
|
download_file(ICON_URL, icon_path) |
|
print("Icon saved to", icon_path) |
|
except Exception: |
|
print("Icon download failed, continuing…") |
|
|
|
desktop_contents = f"""[Desktop Entry] |
|
Name=Cursor AI IDE |
|
Exec={current_path} --no-sandbox |
|
Icon={icon_path} |
|
Terminal=false |
|
Type=Application |
|
Categories=Development;Utility; |
|
Comment=AI‑powered code editor |
|
""" |
|
with open(DESKTOP_FILE, "w") as f: |
|
f.write(desktop_contents) |
|
os.chmod(DESKTOP_FILE, 0o644) |
|
|
|
print("Cursor installation/update complete.") |
https://downloader.cursor.sh/linux/appImage/x64 is not working anymore
Use this script instead