# -*- coding: utf-8 -*- """OpenCreator 文件树统计(可复算) 输入:取证/opencreator/tree_*.json(本棒分片拉取)+ 取证/api/opencreator.tree.top.json(第 1 棒顶层) 输出:取证/opencreator/opencreator.tree.stat.json + 控制台摘要 口径:只数 type=='blob';顶层目录取 path 第一段。 """ import json, os, collections HERE = os.path.dirname(os.path.abspath(__file__)) OC = os.path.join(HERE, "opencreator") API = os.path.join(HERE, "api") # 切片树里的 path 是相对「该切片根」的,必须补回前缀才是仓根相对路径 SLICES = { "tree_.github.json": ".github", "tree_apps.json": "apps", "tree_assets.json": "assets", "tree_packages.json": "packages", "tree_resources.json": "resources", "tree_runtime.json": "runtime", "tree_scripts.json": "scripts", "tree_skills.json": "skills", "tree_template.json": "template", "tree_docs.json": "docs", } blobs = [] # (path, size) trees = 0 for f, prefix in SLICES.items(): d = json.load(open(os.path.join(OC, f), encoding="utf-8")) assert not d.get("truncated"), f + " truncated" for e in d["tree"]: if e["type"] == "blob": blobs.append((prefix + "/" + e["path"], e.get("size", 0))) else: trees += 1 root = json.load(open(os.path.join(API, "opencreator.tree.top.json"), encoding="utf-8")) for e in root["tree"]: if e["type"] == "blob": blobs.append((e["path"], e.get("size", 0))) else: trees += 1 # 去重(docs/specs 在 docs 整树里已含) seen, uniq = set(), [] for p, s in blobs: if p in seen: continue seen.add(p) uniq.append((p, s)) blobs = uniq by_top = collections.Counter() for p, _ in blobs: by_top[p.split("/")[0]] += 1 def sub(prefix, n=2): c = collections.Counter() for p, _ in blobs: if p.startswith(prefix + "/"): parts = p.split("/") c["/".join(parts[:n])] += 1 return c ext = collections.Counter() for p, _ in blobs: ext[os.path.splitext(p)[1].lower() or "(noext)"] += 1 apps = sub("apps", 3) daemon_src = collections.Counter() for p, _ in blobs: if p.startswith("apps/daemon/src/"): parts = p.split("/") daemon_src["/".join(parts[:4]) if len(parts) > 3 else "/".join(parts[:3])] += 1 web_src = collections.Counter() for p, _ in blobs: if p.startswith("apps/web/src/"): parts = p.split("/") web_src["/".join(parts[:4]) if len(parts) > 3 else "/".join(parts[:3])] += 1 rt = sub("runtime/krillinai", 3) tpl = collections.Counter() for p, _ in blobs: if p.startswith("template/"): parts = p.split("/") tpl[parts[1]] += 1 # 模板条目数(二级目录) tpl_entries = collections.Counter() for p, _ in blobs: if p.startswith("template/") and len(p.split("/")) >= 3: tpl_entries["/".join(p.split("/")[:2])] += 1 # writing-templates 模板条目 wt = collections.Counter() for p, _ in blobs: if p.startswith("packages/writing-templates/templates/"): wt["/".join(p.split("/")[:4])] += 1 test_files = [p for p, _ in blobs if ".test." in p or ".spec." in p] out = { "repo": "krillinai/OpenCreator", "branch": "master", "total_blobs": len(blobs), "total_trees": trees, "total_bytes": sum(s for _, s in blobs), "blobs_by_top_dir": dict(by_top.most_common()), "ext_top20": dict(ext.most_common(20)), "apps_by_3": dict(apps.most_common()), "apps_daemon_src": dict(daemon_src.most_common()), "apps_web_src": dict(web_src.most_common()), "runtime_krillinai": dict(rt.most_common()), "template_by_category": dict(tpl.most_common()), "template_entries_by_category": {k: sum(1 for p, _ in blobs if p.startswith(k + "/")) for k in tpl}, "writing_templates_entries": dict(wt.most_common()), "test_file_count": len(test_files), "test_files_sample": test_files[:15], } with open(os.path.join(OC, "opencreator.tree.stat.json"), "w", encoding="utf-8") as f: json.dump(out, f, ensure_ascii=False, indent=1) print("total_blobs=%d total_trees=%d total_bytes=%d test_files=%d" % (len(blobs), trees, out["total_bytes"], len(test_files))) print("顶层目录 blob 数:", dict(by_top.most_common())) print() print("apps 三层:", dict(apps.most_common(12))) print() print("daemon/src 四层:", dict(daemon_src.most_common(15))) print() print("web/src 四层:", dict(web_src.most_common(15))) print() print("runtime/krillinai 三层:", dict(rt.most_common(20))) print() print("template 分类 blob 数:", dict(tpl.most_common())) print("template 条目数(二级目录):", dict(out["template_entries_by_category"])) print() print("writing-templates 条目:", dict(wt.most_common())) print() print("扩展名 top20:", dict(ext.most_common(20)))