From 0e3c7b85403a86ae837166845a9ebee87daba0ac Mon Sep 17 00:00:00 2001 From: ghangz <152254226+ghangz@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:43:03 +0800 Subject: [PATCH 1/2] Add kernel inventory exporter --- tools/kernel_inventory.py | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tools/kernel_inventory.py diff --git a/tools/kernel_inventory.py b/tools/kernel_inventory.py new file mode 100644 index 0000000..aced3b1 --- /dev/null +++ b/tools/kernel_inventory.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""Export a JSON inventory of mcoplib kernel files.""" + +from __future__ import annotations + + +import argparse +import json +from pathlib import Path + + +PATTERNS = ['kernel/**/*', 'op/**/*.cu', 'include/**/*'] + + +def inventory(root: Path) -> dict[str, object]: + files: list[dict[str, object]] = [] + for pattern in PATTERNS: + for path in sorted(root.glob(pattern)): + if path.is_file(): + rel = path.relative_to(root).as_posix() + files.append({"path": rel, "bytes": path.stat().st_size, "pattern": pattern}) + by_pattern: dict[str, int] = {} + for item in files: + by_pattern[item["pattern"]] = by_pattern.get(item["pattern"], 0) + 1 + return {"root": str(root), "count": len(files), "by_pattern": by_pattern, "files": files} + + +def self_test() -> None: + data = inventory(Path.cwd()) + assert isinstance(data["files"], list) + print(json.dumps({"ok": True, "count": data["count"]}, ensure_ascii=False)) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--root", default=".", help="Repository root to scan.") + parser.add_argument("--self-test", action="store_true") + args = parser.parse_args() + if args.self_test: + self_test() + return 0 + print(json.dumps(inventory(Path(args.root)), ensure_ascii=False, indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 6578ce49e36630ab3b0cd5bea634862f0b032967 Mon Sep 17 00:00:00 2001 From: ghangz <152254226+ghangz@users.noreply.github.com> Date: Wed, 1 Jul 2026 15:45:24 +0800 Subject: [PATCH 2/2] Validate kernel inventory root --- tools/kernel_inventory.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/tools/kernel_inventory.py b/tools/kernel_inventory.py index aced3b1..43acd30 100644 --- a/tools/kernel_inventory.py +++ b/tools/kernel_inventory.py @@ -9,25 +9,36 @@ from pathlib import Path -PATTERNS = ['kernel/**/*', 'op/**/*.cu', 'include/**/*'] +PATTERNS = ["kernel/**/*", "op/**/*.cu", "include/**/*"] def inventory(root: Path) -> dict[str, object]: + if not root.is_dir(): + raise NotADirectoryError(f"inventory root is not a directory: {root}") + files: list[dict[str, object]] = [] for pattern in PATTERNS: for path in sorted(root.glob(pattern)): if path.is_file(): rel = path.relative_to(root).as_posix() - files.append({"path": rel, "bytes": path.stat().st_size, "pattern": pattern}) + files.append( + {"path": rel, "bytes": path.stat().st_size, "pattern": pattern} + ) by_pattern: dict[str, int] = {} for item in files: by_pattern[item["pattern"]] = by_pattern.get(item["pattern"], 0) + 1 - return {"root": str(root), "count": len(files), "by_pattern": by_pattern, "files": files} + return { + "root": str(root), + "count": len(files), + "by_pattern": by_pattern, + "files": files, + } def self_test() -> None: data = inventory(Path.cwd()) - assert isinstance(data["files"], list) + if not isinstance(data["files"], list): + raise RuntimeError(f"self-test failed: {data}") print(json.dumps({"ok": True, "count": data["count"]}, ensure_ascii=False)) @@ -39,7 +50,10 @@ def main() -> int: if args.self_test: self_test() return 0 - print(json.dumps(inventory(Path(args.root)), ensure_ascii=False, indent=2)) + root = Path(args.root) + if not root.is_dir(): + parser.error(f"--root is not a directory: {root}") + print(json.dumps(inventory(root), ensure_ascii=False, indent=2)) return 0