Takuto Ikuta | fc72225 | 2024-01-24 14:49:20 +0900 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Alfred Zien | 6523a5f | 2020-05-08 21:52:14 +0300 | [diff] [blame] | 2 | # Copyright 2020 The Chromium Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | |
| 7 | """ |
| 8 | Finds unreachable gn targets by analysing --ide=json output |
| 9 | from gn gen. |
| 10 | |
| 11 | Usage: |
| 12 | # Generate json file with targets info, will be located at out/project.json: |
| 13 | gn gen out --ide=json |
| 14 | # Lists all targets that are not reachable from //:all or //ci:test_all: |
| 15 | find_unreachable.py --from //:all --from //ci:test_all --json-file out/project.json |
| 16 | # Lists targets unreachable from //:all that aren't referenced by any other target: |
| 17 | find_unreachable.py --from //:all --json-file out/project.json --no-refs |
| 18 | """ |
| 19 | |
| 20 | import argparse |
| 21 | import json |
| 22 | import sys |
| 23 | |
| 24 | |
| 25 | def find_reachable_targets(known, graph): |
| 26 | reachable = set() |
| 27 | to_visit = known |
| 28 | while to_visit: |
| 29 | next = to_visit.pop() |
| 30 | if next in reachable: |
| 31 | continue |
| 32 | reachable.add(next) |
| 33 | to_visit += graph[next]['deps'] |
| 34 | return reachable |
| 35 | |
| 36 | |
| 37 | def find_source_targets_from(targets, graph): |
| 38 | source_targets = set(targets) |
| 39 | for target in targets: |
| 40 | source_targets -= set(graph[target]['deps']) |
| 41 | return source_targets |
| 42 | |
| 43 | |
| 44 | def main(): |
| 45 | parser = argparse.ArgumentParser(description=''' |
| 46 | Tool to find unreachable targets. |
| 47 | This can be useful to inspect forgotten targets, |
| 48 | for example tests or intermediate targets in templates |
| 49 | that are no longer needed. |
| 50 | ''') |
| 51 | parser.add_argument( |
| 52 | '--json-file', required=True, |
| 53 | help='JSON file from gn gen with --ide=json option') |
| 54 | parser.add_argument( |
| 55 | '--from', action='append', dest='roots', |
| 56 | help='Known "root" targets. Can be multiple. Those targets \ |
| 57 | and all their recursive dependencies are considered reachable.\ |
| 58 | Examples: //:all, //ci:test_all') |
| 59 | parser.add_argument( |
| 60 | '--no-refs', action='store_true', |
| 61 | help='Show only targets that aren\'t referenced by any other target') |
| 62 | cmd_args = parser.parse_args() |
| 63 | |
| 64 | with open(cmd_args.json_file) as json_file: |
| 65 | targets_graph = json.load(json_file)['targets'] |
| 66 | |
| 67 | reachable = find_reachable_targets(cmd_args.roots, targets_graph) |
| 68 | all = set(targets_graph.keys()) |
| 69 | unreachable = all - reachable |
| 70 | |
| 71 | result = find_source_targets_from(unreachable, targets_graph) \ |
| 72 | if cmd_args.no_refs else unreachable |
| 73 | |
Takuto Ikuta | fc72225 | 2024-01-24 14:49:20 +0900 | [diff] [blame] | 74 | print('\n'.join(sorted(result))) |
Alfred Zien | 6523a5f | 2020-05-08 21:52:14 +0300 | [diff] [blame] | 75 | |
| 76 | |
| 77 | if __name__ == '__main__': |
| 78 | sys.exit(main()) |