-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloc.py
More file actions
106 lines (87 loc) · 3.47 KB
/
cloc.py
File metadata and controls
106 lines (87 loc) · 3.47 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
101
102
103
104
105
106
"""Provide a wrapper for counting lines of code using the cloc tool.
This module contains the `Cloc` class, a wrapper around the `cloc` tool,
to calculate the number of physical lines of source code for a specific
language within a directory.
"""
import json
import shutil
from pathlib import Path
from codesectools.utils import USER_CACHE_DIR, MissingFile, NonZeroExit, run_command
class Cloc:
"""A wrapper for the 'cloc' (Count Lines of Code) tool.
Find the 'cloc' executable or download and use the Perl script if the
executable is not available but Perl is. Provide a method to count
lines of code for a specific language.
Attributes:
version (str): The version of the cloc Perl script to download.
cloc_names (dict): A mapping from internal language names to the names
used by cloc.
dir (Path): The directory to run cloc in.
lang (str): The programming language to count, mapped to the cloc name.
base_command (list[str]): The command list to execute cloc.
"""
version = "2.06"
cloc_names = {"java": "Java", "c": "C"}
def __init__(self, dir: Path, lang: str) -> None:
"""Initialize the Cloc wrapper.
Check for the 'cloc' binary. If not found, check for 'perl' and
download the 'cloc.pl' script if it doesn't exist locally.
Args:
dir: The directory to run cloc in.
lang: The programming language to count.
"""
from git import Repo
self.dir = dir
self.lang = self.cloc_names.get(lang)
if shutil.which("cloc"):
self.base_command = ["cloc", ".", "--json"]
else:
if shutil.which("perl"):
cloc_repo = USER_CACHE_DIR / "cloc"
if not cloc_repo.is_dir():
repo = Repo.clone_from(
"https://github.com/AlDanial/cloc.git",
cloc_repo,
depth=1,
sparse=True,
filter=["tree:0"],
)
repo.git.sparse_checkout(
"set",
"--no-cone",
*[
"cloc",
"LICENSE",
],
)
self.base_command = [
"perl",
str(USER_CACHE_DIR / "cloc" / "cloc"),
".",
"--json",
]
else:
raise MissingFile(["perl", "cloc"])
def get_loc(self) -> int:
"""Get the lines of code for the specified language.
Execute the cloc command, parse the JSON output, and return the
number of source code lines.
Returns:
The number of lines of code, or 0 if the language is not found
in the output or -1 if the language is not supported by
CodeSecTools.
Raises:
NonZeroExit: If the cloc command fails.
"""
if self.lang:
full_command = self.base_command + [f"--include-lang={self.lang}"]
retcode, out = run_command(full_command, self.dir)
if retcode != 0:
raise NonZeroExit(full_command, out)
json_out = json.loads(out)
if lang_stats := json_out.get(self.lang):
return lang_stats["code"]
else:
return 0
else:
return -1