-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdate_check.py
More file actions
112 lines (89 loc) · 3.16 KB
/
Copy pathupdate_check.py
File metadata and controls
112 lines (89 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""
Background version check against GitHub Releases.
Usage:
# Start the check (call once from a daemon thread):
threading.Thread(target=check_for_update, daemon=True).start()
# Query the cached result (from any thread):
info = get_update_info() # None or {"version", "url", "download_url"}
"""
import json
import platform
import subprocess
import sys
import threading
import time
import urllib.request
from pathlib import Path
from packaging.version import Version, InvalidVersion
from config import APP_VERSION, GITHUB_OWNER, GITHUB_REPO
def _asset_suffix():
"""Return the expected file extension for this platform's release asset."""
if sys.platform == "darwin":
return ".dmg"
elif sys.platform == "win32":
return ".exe"
else:
return ".tar.gz"
_latest = None
_done = False
_lock = threading.Lock()
_API_URL = f"https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}/releases/latest"
def check_for_update():
"""Check GitHub for a newer release. Runs in a background thread."""
global _latest, _done
time.sleep(5)
try:
req = urllib.request.Request(_API_URL, headers={"Accept": "application/vnd.github+json"})
with urllib.request.urlopen(req, timeout=5) as resp:
data = json.loads(resp.read())
tag = data.get("tag_name", "")
remote_version = tag.lstrip("v")
if Version(remote_version) <= Version(APP_VERSION):
return
# Find the asset matching this platform (.dmg / .exe / .tar.gz)
suffix = _asset_suffix()
download_url = None
for asset in data.get("assets", []):
if asset.get("name", "").endswith(suffix):
download_url = asset["browser_download_url"]
break
with _lock:
_latest = {
"version": remote_version,
"url": data.get("html_url", ""),
"download_url": download_url,
}
except Exception:
pass
finally:
_done = True
def get_update_info():
"""Return cached update info, or None if up to date / not checked yet."""
with _lock:
return _latest
def is_check_done():
"""Return True once the background check has completed (success or failure)."""
return _done
def download_update():
"""Download the .dmg to ~/Downloads and reveal in Finder. Returns the path."""
info = get_update_info()
if not info or not info.get("download_url"):
return None
suffix = _asset_suffix()
dest = Path.home() / "Downloads" / f"Datamarkin-{info['version']}{suffix}"
req = urllib.request.Request(info["download_url"])
with urllib.request.urlopen(req, timeout=120) as resp:
with open(dest, "wb") as f:
while True:
chunk = resp.read(8192)
if not chunk:
break
f.write(chunk)
# Reveal in file manager
if sys.platform == "darwin":
subprocess.Popen(["open", "-R", str(dest)])
elif sys.platform == "win32":
subprocess.Popen(["explorer", "/select,", str(dest)])
else:
subprocess.Popen(["xdg-open", str(dest.parent)])
return str(dest)