blob: 406a312b537071e9d510b53e50c07d514ba24c6a [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Finds unreachable gn targets by analysing --ide=json output
from gn gen.
Usage:
# Generate json file with targets info, will be located at out/project.json:
gn gen out --ide=json
# Lists all targets that are not reachable from //:all or //ci:test_all:
find_unreachable.py --from //:all --from //ci:test_all --json-file out/project.json
# Lists targets unreachable from //:all that aren't referenced by any other target:
find_unreachable.py --from //:all --json-file out/project.json --no-refs
"""
import argparse
import json
import sys
def find_reachable_targets(known, graph):
reachable = set()
to_visit = known
while to_visit:
next = to_visit.pop()
if next in reachable:
continue
reachable.add(next)
to_visit += graph[next]['deps']
return reachable
def find_source_targets_from(targets, graph):
source_targets = set(targets)
for target in targets:
source_targets -= set(graph[target]['deps'])
return source_targets
def main():
parser = argparse.ArgumentParser(description='''
Tool to find unreachable targets.
This can be useful to inspect forgotten targets,
for example tests or intermediate targets in templates
that are no longer needed.
''')
parser.add_argument(
'--json-file', required=True,
help='JSON file from gn gen with --ide=json option')
parser.add_argument(
'--from', action='append', dest='roots',
help='Known "root" targets. Can be multiple. Those targets \
and all their recursive dependencies are considered reachable.\
Examples: //:all, //ci:test_all')
parser.add_argument(
'--no-refs', action='store_true',
help='Show only targets that aren\'t referenced by any other target')
cmd_args = parser.parse_args()
with open(cmd_args.json_file) as json_file:
targets_graph = json.load(json_file)['targets']
reachable = find_reachable_targets(cmd_args.roots, targets_graph)
all = set(targets_graph.keys())
unreachable = all - reachable
result = find_source_targets_from(unreachable, targets_graph) \
if cmd_args.no_refs else unreachable
print '\n'.join(sorted(result))
if __name__ == '__main__':
sys.exit(main())