|  | #!/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()) |