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
|
#!/usr/bin/env python
"""
Make tags for internal or external code.
This should run fast, and be executable with just Python, meaning it does not
require a build step.
"""
# : out maketags
# : run universal-ctags
import argparse
import os
import pathlib
import subprocess
import tarfile
import zipfile
def main() -> None:
"""Run ctags on internal or external source code.
Raises:
ValueError: if CODEROOT is not set
ArgumentError: when explicit paths aren't provided
"""
coderoot = os.environ.get("CODEROOT")
if coderoot is None:
msg = "CODEROOT not set"
raise ValueError(msg)
cabsrc = pathlib.Path(coderoot) / "_" / "src"
cli = argparse.ArgumentParser()
cli.add_argument(
"paths",
nargs="*",
default=".",
help="List of paths to run ctags on. Defaults to '.'",
)
cli.add_argument(
"-x",
"--external",
action="store_true",
help=" ".join([
"Use this when `paths` is a list of external packages,",
f"they will be extracted or linked into {cabsrc}",
]),
)
args = cli.parse_args()
if args.external and args.paths == ".":
msg = "requires explicit paths"
raise argparse.ArgumentError(argument=args.external, message=msg)
if args.external:
extract_and_copy(cabsrc, args.paths)
ctags(["--recurse=yes"], cwd=cabsrc)
else:
ctags(["--exclude=*_/*", "--recurse=yes"], cwd=pathlib.Path(coderoot))
def strip_nix_hash(path: str) -> str:
"""Remove the /nix/store/ and hash prefix from a path."""
hash_len = 33
return path.removeprefix("/nix/store/")[hash_len:]
def extract_and_copy(cabsrc: pathlib.Path, paths: list[str]) -> None:
"""
Extract and copy or link sources.
Loop over `paths`, if the path is an archive, extract it into `cabsrc`. If
its a directory, just symlink the directory into `cabsrc`. Either way, we
end up with a directory full of source trees for running ctags on.
"""
for path in paths:
outpath: pathlib.Path = cabsrc / strip_nix_hash(path)
if outpath.exists():
continue
if path.endswith(".zip"):
out = outpath.with_suffix("")
if out.exists():
continue
zipfile.ZipFile(path).extractall(out) # noqa: S202
elif path.endswith(".tar.gz"):
out = outpath.with_suffix("").with_suffix("")
if out.exists():
continue
with tarfile.open(path) as tarball:
tarball.extractall(out) # noqa: S202
elif pathlib.Path(path).is_dir():
outpath.symlink_to(path)
def ctags(args: list[str], cwd: pathlib.Path = pathlib.Path()) -> None:
"""Call `ctags` with `args` for both emacs and vim."""
os.chdir(cwd)
excludes = [
"--exclude=.mypy_cache",
"--exclude=.git",
"--exclude=.direnv",
"--exclude=.ruff_cache",
]
subprocess.check_call(["ctags", *excludes, *args])
subprocess.check_call(["ctags", "-e", *excludes, *args])
|