mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
107 lines
3.4 KiB
Python
Executable File
107 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
fetch_prebuilt_frontend.py
|
|
|
|
Downloads the latest prebuilt frontend artifact from the GitHub releases page
|
|
and installs it into frontend/prebuilt/ so the backend can serve it directly.
|
|
|
|
No GitHub CLI or authentication required — uses only the public releases API
|
|
and browser_download_url. Requires only the Python standard library.
|
|
"""
|
|
|
|
import json
|
|
import shutil
|
|
import sys
|
|
import urllib.request
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
REPO = "jkingsman/Remote-Terminal-for-MeshCore"
|
|
API_URL = f"https://api.github.com/repos/{REPO}/releases/latest"
|
|
PREBUILT_PREFIX = "Remote-Terminal-for-MeshCore/frontend/prebuilt/"
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
PREBUILT_DIR = SCRIPT_DIR.parent / "frontend" / "prebuilt"
|
|
|
|
|
|
def fetch_json(url: str) -> dict:
|
|
req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json"})
|
|
with urllib.request.urlopen(req) as resp:
|
|
return json.loads(resp.read())
|
|
|
|
|
|
def find_prebuilt_asset(release: dict) -> tuple[str, str, str]:
|
|
"""Return (tag_name, asset_name, download_url) for the prebuilt zip."""
|
|
tag = release.get("tag_name", "")
|
|
for asset in release.get("assets", []):
|
|
name = asset.get("name", "")
|
|
if name.startswith("remoteterm-prebuilt-frontend-") and name.endswith(".zip"):
|
|
return tag, name, asset["browser_download_url"]
|
|
raise SystemExit(
|
|
f"No prebuilt frontend artifact found in the latest release.\n"
|
|
f"Check https://github.com/{REPO}/releases for available assets."
|
|
)
|
|
|
|
|
|
def download(url: str, dest: Path) -> None:
|
|
with urllib.request.urlopen(url) as resp, open(dest, "wb") as f:
|
|
shutil.copyfileobj(resp, f)
|
|
|
|
|
|
def extract_prebuilt(zip_path: Path, dest: Path) -> int:
|
|
with zipfile.ZipFile(zip_path) as zf:
|
|
members = [m for m in zf.namelist() if m.startswith(PREBUILT_PREFIX)]
|
|
if not members:
|
|
raise SystemExit(f"'{PREBUILT_PREFIX}' not found inside zip.")
|
|
|
|
if dest.exists():
|
|
shutil.rmtree(dest)
|
|
dest.mkdir(parents=True)
|
|
|
|
for member in members:
|
|
rel = member[len(PREBUILT_PREFIX):]
|
|
if not rel:
|
|
continue
|
|
target = dest / rel
|
|
if member.endswith("/"):
|
|
target.mkdir(parents=True, exist_ok=True)
|
|
else:
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
with zf.open(member) as src, open(target, "wb") as dst:
|
|
shutil.copyfileobj(src, dst)
|
|
|
|
return len(members)
|
|
|
|
|
|
def main() -> None:
|
|
print("Fetching latest release info...")
|
|
release = fetch_json(API_URL)
|
|
tag, asset_name, download_url = find_prebuilt_asset(release)
|
|
print(f" Release : {tag}")
|
|
print(f" Asset : {asset_name}")
|
|
print()
|
|
|
|
zip_path = PREBUILT_DIR.parent / asset_name
|
|
try:
|
|
print(f"Downloading {asset_name}...")
|
|
download(download_url, zip_path)
|
|
|
|
print("Extracting prebuilt frontend...")
|
|
count = extract_prebuilt(zip_path, PREBUILT_DIR)
|
|
print(f"Extracted {count} entries.")
|
|
finally:
|
|
zip_path.unlink(missing_ok=True)
|
|
|
|
print()
|
|
print(f"Done! Prebuilt frontend ({tag}) installed to frontend/prebuilt/")
|
|
print("Start the server with:")
|
|
print(" uv run uvicorn app.main:app --host 0.0.0.0 --port 8000")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
print("\nAborted.", file=sys.stderr)
|
|
sys.exit(1)
|