From 2d145e7c9473b48dc7ee1879deaa4d28053fbca5 Mon Sep 17 00:00:00 2001 From: I-Al-Istannen Date: Mon, 24 Oct 2022 17:31:34 +0200 Subject: [PATCH] Check for new versions at startup --- PFERD/__main__.py | 7 ++++++ PFERD/cli/parser.py | 5 +++++ PFERD/update.py | 53 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 PFERD/update.py diff --git a/PFERD/__main__.py b/PFERD/__main__.py index 4faeb13..19f5a21 100644 --- a/PFERD/__main__.py +++ b/PFERD/__main__.py @@ -5,6 +5,8 @@ import os import sys from pathlib import Path +from PFERD.update import check_for_updates + from .auth import AuthLoadError from .cli import PARSER, ParserLoadError, load_default_section from .config import Config, ConfigDumpError, ConfigLoadError, ConfigOptionError @@ -134,6 +136,11 @@ def main() -> None: loop.run_until_complete(asyncio.sleep(1)) loop.close() else: + log.explain_topic("Checking for updates") + if not args.skip_update_check: + asyncio.run(check_for_updates()) + else: + log.explain("Update check skipped due to configuration option") asyncio.run(pferd.run(args.debug_transforms)) except (ConfigOptionError, AuthLoadError) as e: log.unlock() diff --git a/PFERD/cli/parser.py b/PFERD/cli/parser.py index e753023..2868d38 100644 --- a/PFERD/cli/parser.py +++ b/PFERD/cli/parser.py @@ -151,6 +151,11 @@ PARSER.add_argument( action="version", version=f"{NAME} {VERSION} (https://github.com/Garmelon/PFERD)", ) +PARSER.add_argument( + "--skip-update-check", + action="store_true", + help="disable automatic update checks at startup" +) PARSER.add_argument( "--config", "-c", type=Path, diff --git a/PFERD/update.py b/PFERD/update.py new file mode 100644 index 0000000..ff86368 --- /dev/null +++ b/PFERD/update.py @@ -0,0 +1,53 @@ +from dataclasses import dataclass +import ssl +from typing import Optional +import aiohttp +import certifi + +from .version import NAME, VERSION +from .logging import log + + +@dataclass +class PferdUpdate: + release_url: str + version: str + + +def _build_session() -> aiohttp.ClientSession: + return aiohttp.ClientSession( + headers={"User-Agent": f"{NAME}/{VERSION}"}, + connector=aiohttp.TCPConnector(ssl=ssl.create_default_context(cafile=certifi.where())), + timeout=aiohttp.ClientTimeout( + total=15 * 60, + connect=10, + sock_connect=10, + sock_read=10, + ) + ) + + +async def check_for_updates() -> None: + if new_version := await get_newer_version(): + log.warn( + f"{NAME} version out of date. " + + f"You are running version {VERSION!r} but {new_version.version!r} was found on GitHub." + ) + log.warn_contd(f"You can download it on GitHub: {new_version.release_url}") + else: + log.explain("No update found") + + +async def get_newer_version() -> Optional[PferdUpdate]: + async with _build_session() as session: + async with session.get( + "https://api.github.com/repos/Garmelon/Pferd/releases/latest", + headers={"Accept": "application/vnd.github+json"} + ) as response: + release_information = await response.json() + tag_name: str = release_information["tag_name"] + tag_name = tag_name.removeprefix("v") + if VERSION == tag_name: + return None + + return PferdUpdate(release_url=release_information["html_url"], version=tag_name)