From 36df64cedad5019e62b1d3469a9cdabef88fc308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pi=C3=A9dallu?= Date: Thu, 7 Mar 2024 23:14:07 +0100 Subject: [PATCH] Add a crappy script that finds deprecated apps tl;dr, only working for github and gitlab upstreams, checks if the latest commit is more than 1 year old. It also removes deprecated-software if required. --- tools/find_deprecated.py | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100755 tools/find_deprecated.py diff --git a/tools/find_deprecated.py b/tools/find_deprecated.py new file mode 100755 index 00000000..d860ac20 --- /dev/null +++ b/tools/find_deprecated.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 + +import argparse +import tomlkit +import multiprocessing +import datetime +import json +import sys +from functools import cache +import logging +from pathlib import Path +from typing import Optional + +import toml +import tqdm +import github + +# add apps/tools to sys.path +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from appslib.utils import REPO_APPS_ROOT, get_catalog # noqa: E402 pylint: disable=import-error,wrong-import-position +from app_caches import app_cache_folder # noqa: E402 pylint: disable=import-error,wrong-import-position +from autoupdate_app_sources.rest_api import GithubAPI, GitlabAPI, GiteaForgejoAPI, RefType # noqa: E402,E501 pylint: disable=import-error,wrong-import-position + + +@cache +def get_github() -> tuple[Optional[tuple[str, str]], Optional[github.Github], Optional[github.InputGitAuthor]]: + try: + github_login = (REPO_APPS_ROOT / ".github_login").open("r", encoding="utf-8").read().strip() + github_token = (REPO_APPS_ROOT / ".github_token").open("r", encoding="utf-8").read().strip() + github_email = (REPO_APPS_ROOT / ".github_email").open("r", encoding="utf-8").read().strip() + + auth = (github_login, github_token) + github_api = github.Github(github_token) + author = github.InputGitAuthor(github_login, github_email) + return auth, github_api, author + except Exception as e: + logging.warning(f"Could not get github: {e}") + return None, None, None + + + +def upstream_last_update_ago(app: str) -> tuple[str, int | None]: + manifest_toml = app_cache_folder(app) / "manifest.toml" + manifest_json = app_cache_folder(app) / "manifest.json" + + if manifest_toml.exists(): + manifest = toml.load(manifest_toml.open("r", encoding="utf-8")) + upstream = manifest.get("upstream", {}).get("code") + + elif manifest_json.exists(): + manifest = json.load(manifest_json.open("r", encoding="utf-8")) + upstream = manifest.get("upstream", {}).get("code") + else: + raise RuntimeError(f"App {app} doesn't have a manifest!") + + if upstream is None: + raise RuntimeError(f"App {app} doesn't have an upstream code link!") + + api = None + if upstream.startswith("https://github.com/"): + api = GithubAPI(upstream, auth=get_github()[0]) + + if upstream.startswith("https://gitlab."): + api = GitlabAPI(upstream) + + if upstream.startswith("https://codeberg.org") or upstream.startswith("https://framagit.org"): + api = GiteaForgejoAPI(upstream) + + if not api: + autoupdate = manifest.get("resources", {}).get("sources", {}).get("main", {}).get("autoupdate") + if autoupdate: + strat = autoupdate["strategy"] + if "gitea" in strat or "forgejo" in strat: + api = GiteaForgejoAPI(upstream) + + if api: + last_commit = api.commits()[0] + date = last_commit["commit"]["author"]["date"] + date = datetime.datetime.fromisoformat(date) + ago: datetime.timedelta = datetime.datetime.now() - date.replace(tzinfo=None) + return app, ago.days + + raise RuntimeError(f"App {app} not handled (not github, gitlab or gitea with autoupdate). Upstream is {upstream}") + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("apps", nargs="*", type=str, + help="If not passed, the script will run on the catalog. Github keys required.") + parser.add_argument("-j", "--processes", type=int, default=multiprocessing.cpu_count()) + args = parser.parse_args() + + apps_dict = get_catalog() + if args.apps: + apps_dict = {app: info for app, info in apps_dict.items() if app in args.apps} + + deprecated: list[str] = [] + not_deprecated: list[str] = [] + # for app, info in apps_dict.items(): + with multiprocessing.Pool(processes=args.processes) as pool: + tasks = pool.imap_unordered(upstream_last_update_ago, apps_dict.keys()) + + for _ in tqdm.tqdm(range(len(apps_dict)), ascii=" ยท#"): + try: + app, result = next(tasks) + except Exception as e: + print(e) + continue + + if result is None: + continue + + if result > 365: + deprecated.append(app) + else: + not_deprecated.append(app) + + catalog = tomlkit.load(open("apps.toml")) + for app, info in catalog.items(): + antifeatures = info.get("antifeatures", []) + if app in deprecated: + if "deprecated-software" not in antifeatures: + antifeatures.append("deprecated-software") + elif app in not_deprecated: + if "deprecated-software" in antifeatures: + antifeatures.remove("deprecated-software") + else: + continue + # unique the keys + if antifeatures: + info["antifeatures"] = antifeatures + else: + if "antifeatures" in info.keys(): + info.pop("antifeatures") + tomlkit.dump(catalog, open("apps.toml", "w")) + + +if __name__ == "__main__": + main()