print_package_dependencies.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #!/usr/bin/env python3
  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. """Command-line tool for printing package-level dependencies."""
  6. import argparse
  7. import graph
  8. import print_dependencies_helper
  9. import serialization
  10. def print_package_dependencies_for_edge(begin, end):
  11. """Prints dependencies for an edge in the package graph.
  12. Since these are package edges, we also print the class dependency edges
  13. comprising the printed package edge.
  14. """
  15. if begin == end:
  16. return
  17. print(f'\t{begin.name} -> {end.name}')
  18. class_deps = begin.get_class_dependencies_in_outbound_edge(end)
  19. print(f'\t{len(class_deps)} class edge(s) comprising the dependency:')
  20. for begin_class, end_class in graph.sorted_edges_by_name(class_deps):
  21. print(f'\t\t{begin_class.class_name} -> {end_class.class_name}')
  22. def print_package_dependencies_for_key(package_graph, key, ignore_subpackages):
  23. """Prints dependencies for a valid key into the package graph.
  24. Since we store self-edges for the package graph
  25. but they aren't relevant in this case, we skip them.
  26. """
  27. node = package_graph.get_node_by_key(key)
  28. inbound_without_self = [other for other in node.inbound if other != node]
  29. print(f'{len(inbound_without_self)} inbound dependency(ies) '
  30. f'for {node.name}:')
  31. for inbound_dep in graph.sorted_nodes_by_name(inbound_without_self):
  32. if ignore_subpackages and inbound_dep.name.startswith(node.name):
  33. continue
  34. print_package_dependencies_for_edge(inbound_dep, node)
  35. outbound_without_self = [other for other in node.outbound if other != node]
  36. print(f'{len(outbound_without_self)} outbound dependency(ies) '
  37. f'for {node.name}:')
  38. for outbound_dep in graph.sorted_nodes_by_name(outbound_without_self):
  39. if ignore_subpackages and outbound_dep.name.startswith(node.name):
  40. continue
  41. print_package_dependencies_for_edge(node, outbound_dep)
  42. def main():
  43. """Prints package-level dependencies for an input package."""
  44. arg_parser = argparse.ArgumentParser(
  45. description='Given a JSON dependency graph, output the package-level '
  46. 'dependencies for a given package and the '
  47. 'class dependencies comprising those dependencies')
  48. required_arg_group = arg_parser.add_argument_group('required arguments')
  49. required_arg_group.add_argument(
  50. '-f',
  51. '--file',
  52. required=True,
  53. help='Path to the JSON file containing the dependency graph. '
  54. 'See the README on how to generate this file.')
  55. required_arg_group.add_argument(
  56. '-p',
  57. '--package',
  58. required=True,
  59. help='Case-insensitive name of the package to print dependencies for. '
  60. 'Matches names of the form ...input, for example '
  61. '`browser` matches `org.chromium.browser`.')
  62. optional_arg_group = arg_parser.add_argument_group('optional arguments')
  63. optional_arg_group.add_argument(
  64. '-s',
  65. '--ignore-subpackages',
  66. action='store_true',
  67. help='If present, this tool will ignore dependencies between the '
  68. 'given package and subpackages. For example, if given '
  69. 'browser.customtabs, it won\'t print a dependency between '
  70. 'browser.customtabs and browser.customtabs.content.')
  71. arguments = arg_parser.parse_args()
  72. _, package_graph, _ = serialization.load_class_and_package_graphs_from_file(
  73. arguments.file)
  74. package_graph_keys = [node.name for node in package_graph.nodes]
  75. valid_keys = print_dependencies_helper.get_valid_package_keys_matching(
  76. package_graph_keys, arguments.package)
  77. if len(valid_keys) == 0:
  78. print(f'No package found by the name {arguments.package}.')
  79. elif len(valid_keys) > 1:
  80. print(f'Multiple valid keys found for the name {arguments.package}, '
  81. 'please disambiguate between one of the following options:')
  82. for valid_key in valid_keys:
  83. print(f'\t{valid_key}')
  84. else:
  85. print(f'Printing package dependencies for {valid_keys[0]}:')
  86. print_package_dependencies_for_key(package_graph, valid_keys[0],
  87. arguments.ignore_subpackages)
  88. if __name__ == '__main__':
  89. main()