-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlanguages.py
More file actions
100 lines (85 loc) · 3.71 KB
/
Copy pathlanguages.py
File metadata and controls
100 lines (85 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin/env python3
"""Répartition des langages sur plusieurs dépôts, en lignes réelles.
Sert à produire les pourcentages du README sans dépendre d'un service tiers
(github-readme-stats ne voit que les dépôts publics, et son instance hébergée
tombe régulièrement). Ici on compte ce qui est sur le disque, dépôts privés
compris.
Usage :
python3 tools/languages.py ../Colibri ../The-new-MEE6 ../elipse-rsai
python3 tools/languages.py --json langs.json <chemins...>
Ce qui est exclu : les dossiers d'artefacts (node_modules, .next, dist, build,
coverage, target, vendor…) et tout ce qui n'a pas d'extension reconnue. On
compte des LIGNES, pas des octets : un binaire commité ne peut pas gonfler le
résultat, et un fichier minifié compte pour ce qu'il est — une ligne.
"""
import argparse
import collections
import json
import os
import sys
EXCLUDE_DIRS = {
"node_modules", ".next", ".git", "dist", "build", "coverage", ".turbo",
"out", ".venv", "__pycache__", ".gradle", "target", "vendor", ".cache",
}
# Plusieurs extensions peuvent pointer vers un même langage (.ts et .tsx).
LANGUAGES = {
".ts": "TypeScript", ".tsx": "TypeScript",
".js": "JavaScript", ".jsx": "JavaScript", ".mjs": "JavaScript", ".cjs": "JavaScript",
".dart": "Dart", ".py": "Python", ".java": "Java", ".kt": "Kotlin",
".ps1": "PowerShell", ".sh": "Shell", ".bash": "Shell",
".sql": "SQL", ".prisma": "Prisma",
".css": "HTML / CSS", ".scss": "HTML / CSS", ".html": "HTML / CSS",
".php": "PHP", ".rs": "Rust", ".go": "Go", ".c": "C", ".cpp": "C++",
}
def count_repo(path):
"""Lignes par langage pour un dépôt. Les fichiers illisibles sont ignorés."""
counts = collections.Counter()
for root, dirs, files in os.walk(path):
dirs[:] = [d for d in dirs if d not in EXCLUDE_DIRS]
for name in files:
lang = LANGUAGES.get(os.path.splitext(name)[1].lower())
if lang is None:
continue
try:
with open(os.path.join(root, name), "rb") as fh:
counts[lang] += sum(1 for _ in fh)
except OSError:
continue
return counts
def main():
ap = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("chemins", nargs="+", help="dépôts à parcourir")
ap.add_argument("--json", help="écrire le résultat dans ce fichier")
ap.add_argument("--seuil", type=float, default=0.1,
help="masquer les langages sous ce pourcentage (défaut 0.1)")
args = ap.parse_args()
total = collections.Counter()
per_repo = {}
for path in args.chemins:
if not os.path.isdir(path):
print(f"ignoré (introuvable) : {path}", file=sys.stderr)
continue
counts = count_repo(path)
per_repo[os.path.basename(os.path.abspath(path))] = dict(counts)
total += counts
grand = sum(total.values())
if not grand:
print("aucune ligne comptée", file=sys.stderr)
return 1
print(f"{len(per_repo)} dépôts — {grand:,} lignes".replace(",", " "))
print("-" * 42)
for lang, n in total.most_common():
pct = 100.0 * n / grand
if pct < args.seuil:
continue
print(f"{lang:<14}{n:>9,}".replace(",", " ") + f"{pct:>7.1f} %")
if args.json:
payload = {"total_lignes": grand, "par_langage": dict(total),
"par_depot": per_repo}
with open(args.json, "w", encoding="utf-8") as fh:
json.dump(payload, fh, ensure_ascii=False, indent=2)
print(f"\n→ JSON écrit : {args.json}")
return 0
if __name__ == "__main__":
sys.exit(main())