#!/usr/bin/env python3 """Scan cloned RISC-V repos and print a compact completeness report.""" import os, subprocess, io, sys sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") REPO_DIR = "/data/repos" REPOS = ["serv", "neorv32", "picorv32", "ibex", "VexRiscv", "e203_hbirdv2", "pulpino", "pulpissimo", "opentitan"] RTL_EXT = {".v", ".sv", ".svh", ".vh", ".vhd", ".vhdl", ".fhdl", ".scala"} TB_DIRS = {"tb", "tb_core", "testbench", "verif", "dv", "dv_uvm", "tests", "test", "tbench"} DOC_EXT = {".md", ".rst", ".tex", ".pdf"} def head_date(repo): try: out = subprocess.run(["git", "log", "-1", "--format=%ci %h"], cwd=os.path.join(REPO_DIR, repo), capture_output=True, text=True).stdout return out.strip()[:16] except Exception: return "?" def scan(repo): root = os.path.join(REPO_DIR, repo) rtl_files = rtl_lines = doc_files = tb_rtl = 0 core_files = makefiles = pyscripts = tcl = bazel = cmake = 0 workflows, licenses = [], [] gitmods = [] for dirpath, dirnames, filenames in os.walk(root): dirnames[:] = [d for d in dirnames if d != ".git"] rel = os.path.relpath(dirpath, root) parts = set(rel.replace("\\", "/").split("/")) for f in filenames: p = os.path.join(dirpath, f) ext = os.path.splitext(f)[1].lower() lf = f.lower() if ext in RTL_EXT: try: with open(p, "rb") as fh: n = sum(1 for _ in fh) except Exception: n = 0 rtl_files += 1 rtl_lines += n if parts & TB_DIRS: tb_rtl += 1 elif ext in DOC_EXT: doc_files += 1 if lf == "license" or lf.startswith("license."): licenses.append(os.path.relpath(p, root)) if lf.endswith(".core"): core_files += 1 if lf in ("makefile",) or lf.startswith("makefile.") or lf.endswith(".mk"): makefiles += 1 if ext == ".py": pyscripts += 1 if ext == ".tcl": tcl += 1 if lf.startswith("bazelrc") or lf == "build" or lf.endswith(".bzl") or lf == "module_bazel": bazel += 1 if lf in ("cmakelists.txt",): cmake += 1 if rel == os.path.join(".github", "workflows"): workflows = [f for f in filenames if f.endswith((".yml", ".yaml"))] gm = os.path.join(root, ".gitmodules") if os.path.exists(gm): with open(gm, encoding="utf-8", errors="ignore") as fh: gitmods = [l.split("=", 1)[1].strip() for l in fh if l.strip().startswith("path =")] tops = sorted(d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d)) and d != ".git") lic = licenses[0] if licenses else "MISSING" readme = os.path.exists(os.path.join(root, "README.md")) or os.path.exists(os.path.join(root, "README.rst")) print(f"=== {repo} ===") print(f"HEAD: {head_date(repo)} | LICENSE: {lic} | README: {'Y' if readme else 'N'}") print(f"RTL files: {rtl_files} | RTL lines: {rtl_lines} | TB rtl files: {tb_rtl} | doc files: {doc_files}") print(f"FuseSoC .core: {core_files} | Makefile: {makefiles} | .py: {pyscripts} | .tcl: {tcl} | bazel-ish: {bazel} | cmake: {cmake}") print(f"CI workflows: {len(workflows)} {workflows[:4]}") print(f"submodules({len(gitmods)}): {gitmods[:12]}") print(f"top dirs: {tops}") print() for r in REPOS: try: scan(r) except Exception as e: print(f"=== {r} === ERROR {e}\n")