import argparse import io import json import subprocess import tarfile import tempfile from datetime import date from html import escape from pathlib import Path import progress SERIES = (("libraries", "System libraries", "#2f81f7"), ("shaders", "GPU shader instructions", "#2ea043")) SHORT = {"libraries": "Libraries", "shaders": "Shaders"} WIDTH, HEIGHT, LEFT, RIGHT, TOP, BOTTOM = 900, 380, 50, 130, 20, 60 MAX_DOTS = 45 BACKGROUND, GRID, TEXT = "#0d1117", "#30363d", "#c9d1d9" def git(*args): return subprocess.run(["git", "-C", str(progress.ROOT), *args], check=True, capture_output=True).stdout def daily_commits(ref): seen = {} for line in git("log", "--first-parent", "--format=%H %cs", ref).decode().splitlines(): sha, day = line.split() seen.setdefault(day, sha) return sorted(seen.items()) def measure(sha): paths = [progress.PRX.relative_to(progress.ROOT).as_posix(), progress.OPCODES.relative_to(progress.ROOT).as_posix()] with tempfile.TemporaryDirectory() as directory: root = Path(directory) try: tarfile.open(fileobj=io.BytesIO(git("archive", sha, "--", *paths))).extractall(root, filter="data") except subprocess.CalledProcessError: return None saved = progress.PRX, progress.OPCODES progress.PRX, progress.OPCODES = root / paths[0], root / paths[1] try: libraries, shaders = progress.collect_libraries(), progress.collect_shaders() except (OSError, AttributeError): return None finally: progress.PRX, progress.OPCODES = saved return {name: {key: data[key] for key in ("done", "total", "percent")} for name, data in (("libraries", libraries), ("shaders", shaders))} def collect(ref): points = [] for day, sha in daily_commits(ref): counts = measure(sha) if counts: points.append({"date": day, "commit": sha, **counts}) return points def labelled(day, span): if span <= 31: return day.strftime("%m-%d") if span <= 150: return day.strftime("%m-%d") if day.weekday() == 0 else "" return day.strftime("%Y-%m") if day.day <= 7 and day.weekday() == 0 else "" def chart(points): days = [date.fromisoformat(p["date"]).toordinal() for p in points] first, span = days[0], max(days[-1] - days[0], 1) top = max(10, int(-(-max(p[name]["percent"] for p in points for name, _, _ in SERIES) // 10) * 10)) px = lambda d: LEFT + (d - first) / span * (WIDTH - LEFT - RIGHT) py = lambda v: TOP + (1 - v / top) * (HEIGHT - TOP - BOTTOM) base = py(0) out = [f'") return "\n".join(out) def page(points): rows = "\n".join(f'
One point per day with commits on main, taken at the last commit of the day. Every point is measured '
f'with the current tools/progress.py rules and instruction list, '
'so the series is comparable across days. Hover a point for the exact numbers. Raw numbers: history.json. '
'Back to the current progress.
| Date | ' + "".join(f'{escape(label)} | % | ' for _, label, _ in SERIES) + '
|---|