1
0
Fork 0
ynh-apps_tools/save_added_date.py
2024-09-12 14:39:40 +02:00

146 lines
4.5 KiB
Python
Executable file

#!/usr/bin/env python3
import argparse
import tomlkit
import json
from datetime import datetime
from git import Repo, Commit
from pathlib import Path
import logging
from typing import Callable
import appslib.get_apps_repo as get_apps_repo
def git_bisect(repo: Repo, is_newer: Callable[[Commit], bool]) -> Commit | None:
# Start with whole repo
first_commit = repo.git.rev_list("HEAD", reverse=True, max_parents=0)
repo.git.bisect("reset")
repo.git.bisect("start", "--no-checkout", "HEAD", first_commit)
while True:
try:
status = "bad" if is_newer(repo.commit("BISECT_HEAD")) else "good"
except Exception:
status = "skip"
result_string = repo.git.bisect(status)
if "is the first bad commit" in result_string.splitlines()[0]:
return repo.commit(result_string.splitlines()[0].split(" ", 1)[0])
def get_app_info(commit: Commit, filebase: str, name: str) -> dict | None:
data = None
try:
filestream = commit.tree.join(f"{filebase}.toml")
filedata = filestream.data_stream.read().decode("utf-8")
dictdata = tomlkit.loads(filedata)
data = dictdata[name]
except KeyError:
pass
try:
filestream = commit.tree.join(f"{filebase}.json")
filedata = filestream.data_stream.read().decode("utf-8")
dictdata = json.loads(filedata)
data = dictdata[name]
except KeyError:
pass
assert isinstance(data, dict) or data is None
return data
def app_is_present(commit: Commit, name: str) -> bool:
info = get_app_info(commit, "apps", name)
# if info is None:
# info = get_app_info(commit, "graveyard", name)
return info is not None
def app_is_deprecated(commit: Commit, name: str) -> bool:
info = get_app_info(commit, "apps", name)
if info is None:
return False
antifeatures = info.get("antifeatures", [])
return "deprecated-software" in antifeatures
def date_added(repo: Repo, name: str) -> int | None:
result = git_bisect(repo, lambda x: app_is_present(x, name))
print(result)
return None if result is None else result.committed_date
def date_deprecated(repo: Repo, name: str) -> int | None:
result = git_bisect(repo, lambda x: app_is_deprecated(x, name))
print(result)
return None if result is None else result.committed_date
def add_deprecation_dates(repo: Repo, file: Path) -> None:
key = "deprecated_date"
document = tomlkit.load(file.open("r", encoding="utf-8"))
for app, info in document.items():
if key in info.keys():
continue
if "deprecated-software" not in info.get("antifeatures", []):
continue
date = date_deprecated(repo, app)
if date is None:
continue
info[key] = date
info[key].comment(datetime.fromtimestamp(info[key]).strftime("%Y/%m/%d"))
info[key].trivia.comment_ws = " "
tomlkit.dump(document, file.open("w"))
def date_added_to(repo: Repo, match: str, file: Path) -> int | None:
commits = repo.git.log(
"-S",
match,
"--first-parent",
"--reverse",
"--date=unix",
"--format=%cd",
"--",
str(file),
).splitlines()
if not commits:
return None
first_commit = commits[0]
return int(first_commit)
def add_apparition_dates(repo: Repo, file: Path, key: str) -> None:
document = tomlkit.load(file.open("r", encoding="utf-8"))
for app, info in document.items():
if key in info.keys():
continue
date = date_added_to(repo, f"[{app}]", file)
assert date is not None
info[key] = date
info[key].comment(datetime.fromtimestamp(info[key]).strftime("%Y/%m/%d"))
info[key].trivia.comment_ws = " "
tomlkit.dump(document, file.open("w"))
def main() -> None:
parser = argparse.ArgumentParser()
get_apps_repo.add_args(parser, allow_temp=False)
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG)
apps_repo_dir = get_apps_repo.from_args(args)
apps_repo = Repo(apps_repo_dir)
add_apparition_dates(apps_repo, apps_repo_dir / "apps.toml", key="added_date")
add_apparition_dates(apps_repo, apps_repo_dir / "wishlist.toml", key="added_date")
add_apparition_dates(apps_repo, apps_repo_dir / "graveyard.toml", key="killed_date")
add_deprecation_dates(apps_repo, apps_repo_dir / "apps.toml")
add_deprecation_dates(apps_repo, apps_repo_dir / "graveyard.toml")
if __name__ == "__main__":
main()