Files
baketnk--frame-yap/scripts/check-update.py
T

64 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""Explicit, bounded GitHub release check. No network access unless --check is passed."""
import argparse
from datetime import datetime
import json
import re
import sys
from urllib import request
RELEASE = re.compile(r"v?((?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.([1-9][0-9]{11}))\Z")
URL = "https://api.github.com/repos/baketnk/frame-yap/releases/latest"
def version(value):
match = RELEASE.fullmatch(value)
if not match:
raise ValueError("invalid release version")
datetime.strptime(match[2], "%Y%m%d%H%M")
return tuple(map(int, match[1].split(".")))
def outcome(payload, current):
data = json.loads(payload)
tag = data["tag_name"]
if not isinstance(tag, str) or not tag.startswith("v"):
raise ValueError("invalid release tag")
candidate = version(tag)
return "AVAILABLE " + tag[1:] if candidate > version(current) else "CURRENT"
class NoRedirect(request.HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None
def check(current):
version(current) # Reject malformed local metadata before making any request.
opener = request.build_opener(request.ProxyHandler({}), NoRedirect())
req = request.Request(URL, headers={"Accept": "application/vnd.github+json", "User-Agent": "FrameYap-update-check"})
with opener.open(req, timeout=6) as response:
payload = response.read(65537)
if len(payload) > 65536:
raise ValueError("oversized response")
return outcome(payload, current)
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--check", action="store_true", help="explicit network check")
parser.add_argument("--current", required=True)
args = parser.parse_args(argv)
if not args.check:
parser.error("--check required for network access")
try:
print(check(args.current), flush=True)
except (ValueError, KeyError, TypeError, OSError):
print("ERROR", flush=True)
return 1
return 0
if __name__ == "__main__":
sys.exit(main())