| # Lint as: 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. |
| """Various helpers for printing dependencies.""" |
| |
| from typing import List |
| |
| import class_dependency |
| import package_dependency |
| |
| |
| def get_valid_classes_from_class_input( |
| class_graph: class_dependency.JavaClassDependencyGraph, |
| class_names_input: str) -> List[str]: |
| """Parses classes given as input into fully qualified, valid classes. |
| |
| Input is a comma-separated list of classes.""" |
| class_names = class_names_input.split(',') |
| return get_valid_classes_from_class_list(class_graph, class_names) |
| |
| |
| def get_valid_classes_from_class_list( |
| class_graph: class_dependency.JavaClassDependencyGraph, |
| class_names: List[str]) -> List[str]: |
| """Parses classes given as input into fully qualified, valid classes. |
| |
| Input is a list of class names.""" |
| result = [] |
| |
| class_graph_keys = [node.name for node in class_graph.nodes] |
| |
| for class_name in class_names: |
| valid_keys = get_valid_class_keys_matching(class_graph_keys, |
| class_name) |
| |
| _check_only_one_valid_key(valid_keys, class_name, 'class') |
| |
| result.append(valid_keys[0]) |
| |
| return result |
| |
| |
| def get_valid_classes_from_package_input( |
| package_graph: package_dependency.JavaPackageDependencyGraph, |
| package_names_input: str) -> List[str]: |
| """Parses packages given as input into fully qualified, valid classes.""" |
| result = [] |
| |
| package_graph_keys = [node.name for node in package_graph.nodes] |
| |
| package_names = package_names_input.split(',') |
| |
| for package_name in package_names: |
| valid_keys = get_valid_package_keys_matching(package_graph_keys, |
| package_name) |
| |
| _check_only_one_valid_key(valid_keys, package_name, 'package') |
| |
| package_key: str = valid_keys[0] |
| package_node: package_dependency.JavaPackage = \ |
| package_graph.get_node_by_key(package_key) |
| classes_in_package: List[str] = sorted(package_node.classes.keys()) |
| result.extend(classes_in_package) |
| |
| return result |
| |
| |
| def _check_only_one_valid_key(valid_keys: List[str], key_input: str, |
| entity: str) -> None: |
| if len(valid_keys) == 0: |
| raise ValueError(f'No {entity} found by the name {key_input}.') |
| elif len(valid_keys) > 1: |
| print(f'Multiple valid keys found for the name {key_input}, ' |
| 'please disambiguate between one of the following options:') |
| for valid_key in valid_keys: |
| print(f'\t{valid_key}') |
| raise ValueError( |
| f'Multiple valid keys found for the name {key_input}.') |
| else: # len(valid_keys) == 1 |
| return |
| |
| |
| def get_valid_package_keys_matching(all_keys: List, |
| input_key: str) -> List[str]: |
| """Return a list of keys of graph nodes that match a package input. |
| |
| For our use case (matching user input to package nodes), |
| a valid key is one that ends with the input, case insensitive. |
| For example, 'apphooks' matches 'org.chromium.browser.AppHooks'. |
| """ |
| input_key_lower = input_key.lower() |
| return [key for key in all_keys if key.lower().endswith(input_key_lower)] |
| |
| |
| def get_valid_class_keys_matching(all_keys: List, input_key: str) -> List[str]: |
| """Return a list of keys of graph nodes that match a class input. |
| |
| For our use case (matching user input to class nodes), |
| a valid key is one that matches fully the input either fully qualified or |
| ignoring package, case sensitive. |
| For example, the inputs 'org.chromium.browser.AppHooks' and 'AppHooks' |
| match the node 'org.chromium.browser.AppHooks' but 'Hooks' does not. |
| """ |
| if '.' in input_key: |
| # Match full name with package only. |
| return [input_key] if input_key in all_keys else [] |
| else: |
| # Match class name in any package. |
| return [key for key in all_keys if key.endswith(f'.{input_key}')] |