Skip to content

Commit 2db0fb6

Browse files
mbolivarcarlescufi
authored andcommitted
scripts: add "west gtags" command
This is an extension for indexing the source code in the workspace with GNU Global. See the command line help for more information about Global. Signed-off-by: Martí Bolívar <marti.bolivar@oss.qualcomm.com>
1 parent 464abe7 commit 2db0fb6

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

scripts/west-commands.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,8 @@ west-commands:
9494
- name: patch
9595
class: Patch
9696
help: manage patches for Zephyr modules
97+
- file: scripts/west_commands/gtags.py
98+
commands:
99+
- name: gtags
100+
class: Gtags
101+
help: create a GNU global tags file for the current workspace

scripts/west_commands/gtags.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Copyright (c) 2025 Qualcomm Innovation Center, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""gtags.py
5+
6+
A west extension for creating tags files (GTAGS) for GNU Global.
7+
For more information on Global, see: https://www.gnu.org/software/global
8+
"""
9+
10+
import argparse
11+
import os.path
12+
import subprocess
13+
import tempfile
14+
15+
from west.commands import WestCommand
16+
17+
18+
class Gtags(WestCommand):
19+
def __init__(self):
20+
super().__init__(
21+
"gtags",
22+
"create a GNU Global tags file for the current workspace",
23+
"""\
24+
Indexes source code files in the west workspace using GNU Global's
25+
"gtags" tool. For more information on Global and gtags, see:
26+
27+
https://www.gnu.org/software/global/
28+
29+
The index can be useful to find definitions of functions, etc.,
30+
especially across repository boundaries. One example is
31+
finding the definition of a vendor HAL function that is
32+
provided by a Zephyr module for the HAL.
33+
34+
By default, this west command only indexes files that are
35+
tracked by git projects defined in the west. Inactive west
36+
projects are ignored by default. For more information on
37+
projects etc., see the west documentation.""",
38+
)
39+
40+
def do_add_parser(self, parser_adder):
41+
parser = parser_adder.add_parser(
42+
self.name,
43+
help=self.help,
44+
description=self.description,
45+
formatter_class=argparse.RawDescriptionHelpFormatter,
46+
)
47+
48+
parser.add_argument(
49+
"projects",
50+
nargs="*",
51+
metavar="PROJECT",
52+
help="""Name of west project to index, or
53+
its path. May be given more than once. Use
54+
"manifest" to refer to the manifest
55+
repository""",
56+
)
57+
58+
return parser
59+
60+
def do_run(self, args, unknown_args):
61+
all_files = []
62+
for project in self.manifest.get_projects(args.projects):
63+
all_files.extend(self.files_in_project(project))
64+
65+
with tempfile.TemporaryDirectory(suffix="gtags") as d:
66+
gtags_files = os.path.join(d, "gtags.files")
67+
with open(gtags_files, "w") as f:
68+
# Due to what looks like a limitation in GNU Global,
69+
# this won't work if there are newlines in file names.
70+
# Unlike xargs and other commands, though, gtags
71+
# doesn't seem to have a way to accept a NUL-delimited
72+
# list of input file; its manpage says file names must
73+
# be delimited by newlines.
74+
f.write("\n".join(all_files))
75+
subprocess.run(
76+
# Note that "gtags -f -" and passing files via stdin
77+
# could run into issues on windows, and there seem to
78+
# be win32 builds of global out there
79+
["gtags", "-f", gtags_files],
80+
cwd=self.manifest.topdir,
81+
check=True,
82+
)
83+
84+
def files_in_project(self, project):
85+
if not project.is_cloned() or not self.manifest.is_active(project):
86+
return []
87+
ls_files = (
88+
project.git(["ls-files", "**"], capture_stdout=True).stdout.decode("utf-8").splitlines()
89+
)
90+
ret = []
91+
for filename in ls_files:
92+
absolute = os.path.join(project.abspath, filename)
93+
# Filter out directories from the git ls-files output.
94+
# There didn't seem to be a way to tell it to do that by
95+
# itself.
96+
if os.path.isfile(absolute):
97+
ret.append(absolute)
98+
return ret

0 commit comments

Comments
 (0)