| #!/usr/bin/env python3 |
| # Copyright 2020 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Command-line tool for printing package-level dependencies.""" |
| |
| import argparse |
| |
| import graph |
| import print_dependencies_helper |
| import serialization |
| |
| |
| def print_package_dependencies_for_edge(begin, end): |
| """Prints dependencies for an edge in the package graph. |
| |
| Since these are package edges, we also print the class dependency edges |
| comprising the printed package edge. |
| """ |
| if begin == end: |
| return |
| print(f'\t{begin.name} -> {end.name}') |
| class_deps = begin.get_class_dependencies_in_outbound_edge(end) |
| print(f'\t{len(class_deps)} class edge(s) comprising the dependency:') |
| for begin_class, end_class in graph.sorted_edges_by_name(class_deps): |
| print(f'\t\t{begin_class.class_name} -> {end_class.class_name}') |
| |
| |
| def print_package_dependencies_for_key(package_graph, key, ignore_subpackages): |
| """Prints dependencies for a valid key into the package graph. |
| |
| Since we store self-edges for the package graph |
| but they aren't relevant in this case, we skip them. |
| """ |
| node = package_graph.get_node_by_key(key) |
| |
| inbound_without_self = [other for other in node.inbound if other != node] |
| print(f'{len(inbound_without_self)} inbound dependency(ies) ' |
| f'for {node.name}:') |
| for inbound_dep in graph.sorted_nodes_by_name(inbound_without_self): |
| if ignore_subpackages and inbound_dep.name.startswith(node.name): |
| continue |
| print_package_dependencies_for_edge(inbound_dep, node) |
| |
| outbound_without_self = [other for other in node.outbound if other != node] |
| print(f'{len(outbound_without_self)} outbound dependency(ies) ' |
| f'for {node.name}:') |
| for outbound_dep in graph.sorted_nodes_by_name(outbound_without_self): |
| if ignore_subpackages and outbound_dep.name.startswith(node.name): |
| continue |
| print_package_dependencies_for_edge(node, outbound_dep) |
| |
| def main(): |
| """Prints package-level dependencies for an input package.""" |
| arg_parser = argparse.ArgumentParser( |
| description='Given a JSON dependency graph, output the package-level ' |
| 'dependencies for a given package and the ' |
| 'class dependencies comprising those dependencies') |
| required_arg_group = arg_parser.add_argument_group('required arguments') |
| required_arg_group.add_argument( |
| '-f', |
| '--file', |
| required=True, |
| help='Path to the JSON file containing the dependency graph. ' |
| 'See the README on how to generate this file.') |
| required_arg_group.add_argument( |
| '-p', |
| '--package', |
| required=True, |
| help='Case-insensitive name of the package to print dependencies for. ' |
| 'Matches names of the form ...input, for example ' |
| '`browser` matches `org.chromium.browser`.') |
| optional_arg_group = arg_parser.add_argument_group('optional arguments') |
| optional_arg_group.add_argument( |
| '-s', |
| '--ignore-subpackages', |
| action='store_true', |
| help='If present, this tool will ignore dependencies between the ' |
| 'given package and subpackages. For example, if given ' |
| 'browser.customtabs, it won\'t print a dependency between ' |
| 'browser.customtabs and browser.customtabs.content.') |
| arguments = arg_parser.parse_args() |
| |
| _, package_graph, _ = serialization.load_class_and_package_graphs_from_file( |
| arguments.file) |
| package_graph_keys = [node.name for node in package_graph.nodes] |
| valid_keys = print_dependencies_helper.get_valid_package_keys_matching( |
| package_graph_keys, arguments.package) |
| |
| if len(valid_keys) == 0: |
| print(f'No package found by the name {arguments.package}.') |
| elif len(valid_keys) > 1: |
| print(f'Multiple valid keys found for the name {arguments.package}, ' |
| 'please disambiguate between one of the following options:') |
| for valid_key in valid_keys: |
| print(f'\t{valid_key}') |
| else: |
| print(f'Printing package dependencies for {valid_keys[0]}:') |
| print_package_dependencies_for_key(package_graph, valid_keys[0], |
| arguments.ignore_subpackages) |
| |
| |
| if __name__ == '__main__': |
| main() |