mirror of
https://github.com/baketnk/frame-yap.git
synced 2026-10-06 09:00:05 +02:00
64 lines
2.1 KiB
Python
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())
|