cdx-manager 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -7
- package/changelogs/CHANGELOGS_0_4_0.md +36 -0
- package/checksums/release-archives.json +9 -0
- package/install.ps1 +21 -1
- package/install.sh +51 -0
- package/package.json +2 -1
- package/pyproject.toml +1 -1
- package/src/backup_bundle.py +134 -0
- package/src/cli.py +54 -4
- package/src/cli_commands.py +242 -13
- package/src/session_service.py +185 -2
- package/src/session_store.py +11 -0
- package/src/status_source.py +3 -1
- package/src/update_check.py +107 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import urllib.error
|
|
4
|
+
import urllib.request
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
UPDATE_CHECK_TTL_SECONDS = 12 * 60 * 60
|
|
9
|
+
LATEST_RELEASE_URL = "https://api.github.com/repos/AlexAgo83/cdx-manager/releases/latest"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _parse_version(value):
|
|
13
|
+
raw = str(value or "").strip().lstrip("v")
|
|
14
|
+
parts = raw.split(".")
|
|
15
|
+
if len(parts) != 3:
|
|
16
|
+
return None
|
|
17
|
+
try:
|
|
18
|
+
return tuple(int(part) for part in parts)
|
|
19
|
+
except ValueError:
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _is_newer_version(current_version, latest_version):
|
|
24
|
+
current = _parse_version(current_version)
|
|
25
|
+
latest = _parse_version(latest_version)
|
|
26
|
+
if not current or not latest:
|
|
27
|
+
return False
|
|
28
|
+
return latest > current
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _cache_path(base_dir):
|
|
32
|
+
return os.path.join(base_dir, "state", "update-check.json")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _read_cache(path):
|
|
36
|
+
try:
|
|
37
|
+
with open(path, "r", encoding="utf-8") as handle:
|
|
38
|
+
return json.load(handle)
|
|
39
|
+
except (FileNotFoundError, OSError, json.JSONDecodeError):
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _write_cache(path, payload):
|
|
44
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
45
|
+
with open(path, "w", encoding="utf-8") as handle:
|
|
46
|
+
json.dump(payload, handle, indent=2)
|
|
47
|
+
handle.write("\n")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _fetch_latest_release():
|
|
51
|
+
request = urllib.request.Request(
|
|
52
|
+
LATEST_RELEASE_URL,
|
|
53
|
+
headers={
|
|
54
|
+
"Accept": "application/vnd.github+json",
|
|
55
|
+
"User-Agent": "cdx-manager-update-check",
|
|
56
|
+
},
|
|
57
|
+
)
|
|
58
|
+
with urllib.request.urlopen(request, timeout=5) as response:
|
|
59
|
+
payload = json.loads(response.read().decode("utf-8"))
|
|
60
|
+
return {
|
|
61
|
+
"latest_version": str(payload.get("tag_name") or "").lstrip("v"),
|
|
62
|
+
"url": payload.get("html_url") or payload.get("url"),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def check_for_update(base_dir, current_version, env=None, now_fn=None):
|
|
67
|
+
env = env or os.environ
|
|
68
|
+
now_fn = now_fn or (lambda: datetime.now(timezone.utc).timestamp())
|
|
69
|
+
if env.get("CDX_DISABLE_UPDATE_CHECK") in {"1", "true", "TRUE", "yes", "YES"}:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
path = _cache_path(base_dir)
|
|
73
|
+
now_ts = float(now_fn())
|
|
74
|
+
cached = _read_cache(path) or {}
|
|
75
|
+
checked_at = cached.get("checked_at")
|
|
76
|
+
if isinstance(checked_at, (int, float)) and (now_ts - checked_at) < UPDATE_CHECK_TTL_SECONDS:
|
|
77
|
+
latest_version = cached.get("latest_version")
|
|
78
|
+
if _is_newer_version(current_version, latest_version):
|
|
79
|
+
return {
|
|
80
|
+
"latest_version": latest_version,
|
|
81
|
+
"url": cached.get("url"),
|
|
82
|
+
"cached": True,
|
|
83
|
+
}
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
latest = _fetch_latest_release()
|
|
88
|
+
except (urllib.error.URLError, TimeoutError, ValueError, OSError):
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
payload = {
|
|
92
|
+
"checked_at": now_ts,
|
|
93
|
+
"latest_version": latest.get("latest_version"),
|
|
94
|
+
"url": latest.get("url"),
|
|
95
|
+
}
|
|
96
|
+
try:
|
|
97
|
+
_write_cache(path, payload)
|
|
98
|
+
except OSError:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
if _is_newer_version(current_version, latest.get("latest_version")):
|
|
102
|
+
return {
|
|
103
|
+
"latest_version": latest.get("latest_version"),
|
|
104
|
+
"url": latest.get("url"),
|
|
105
|
+
"cached": False,
|
|
106
|
+
}
|
|
107
|
+
return None
|