| #!/usr/bin/env python3 | 
 | # 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()) |