| #!/usr/bin/env python3 |
| # |
| # Copyright (C) 2022 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """Utility functions to produce module or module type dependency graphs using json-module-graph or queryview.""" |
| |
| import json |
| import os |
| import os.path |
| import subprocess |
| import xml.etree.ElementTree |
| |
| # This list of module types are omitted from the report and graph |
| # for brevity and simplicity. Presence in this list doesn't mean |
| # that they shouldn't be converted, but that they are not that useful |
| # to be recorded in the graph or report currently. |
| IGNORED_KINDS = set([ |
| "license_kind", |
| "license", |
| "cc_defaults", |
| "cc_prebuilt_object", |
| "cc_prebuilt_library_headers", |
| "cc_prebuilt_library_shared", |
| "cc_prebuilt_library_static", |
| "cc_prebuilt_library_static", |
| "cc_prebuilt_library", |
| "java_defaults", |
| "ndk_prebuilt_static_stl", |
| "ndk_library", |
| ]) |
| |
| SRC_ROOT_DIR = os.path.abspath(__file__ + "/../../../../..") |
| |
| |
| def _build_with_soong(target): |
| subprocess.check_output( |
| [ |
| "build/soong/soong_ui.bash", |
| "--make-mode", |
| "--skip-soong-tests", |
| target, |
| ], |
| cwd=SRC_ROOT_DIR, |
| env={ |
| # Use aosp_arm as the canonical target product. |
| "TARGET_PRODUCT": "aosp_arm", |
| "TARGET_BUILD_VARIANT": "userdebug", |
| }, |
| ) |
| |
| |
| def get_queryview_module_info(module): |
| """Returns the list of transitive dependencies of input module as built by queryview.""" |
| _build_with_soong("queryview") |
| |
| result = subprocess.check_output( |
| [ |
| "tools/bazel", "query", "--config=ci", "--config=queryview", |
| "--output=xml", |
| 'deps(attr("soong_module_name", "^{}$", //...))'.format(module) |
| ], |
| cwd=SRC_ROOT_DIR, |
| ) |
| return xml.etree.ElementTree.fromstring(result) |
| |
| |
| def get_json_module_info(module): |
| """Returns the list of transitive dependencies of input module as provided by Soong's json module graph.""" |
| _build_with_soong("json-module-graph") |
| # Run query.sh on the module graph for the top level module |
| result = subprocess.check_output( |
| [ |
| "build/bazel/json_module_graph/query.sh", "fullTransitiveDeps", |
| "out/soong/module-graph.json", module |
| ], |
| cwd=SRC_ROOT_DIR, |
| ) |
| return json.loads(result) |
| |
| |
| def get_bp2build_converted_modules(): |
| """ Returns the list of modules that bp2build can currently convert. """ |
| _build_with_soong("bp2build") |
| # Parse the list of converted module names from bp2build |
| with open( |
| os.path.join( |
| SRC_ROOT_DIR, |
| "out/soong/soong_injection/metrics/converted_modules.txt")) as f: |
| # Read line by line, excluding comments. |
| # Each line is a module name. |
| ret = [line.strip() for line in f.readlines() if not line.startswith("#")] |
| return set(ret) |
| |
| |
| def get_json_module_type_info(module_type): |
| """Returns the combined transitive dependency closures of all modules of module_type.""" |
| _build_with_soong("json-module-graph") |
| # Run query.sh on the module graph for the top level module type |
| result = subprocess.check_output( |
| [ |
| "build/bazel/json_module_graph/query.sh", |
| "fullTransitiveModuleTypeDeps", "out/soong/module-graph.json", |
| module_type |
| ], |
| cwd=SRC_ROOT_DIR, |
| ) |
| return json.loads(result) |
| |
| |
| def is_windows_variation(module): |
| """Returns True if input module's variant is Windows. |
| |
| Args: |
| module: an entry parsed from Soong's json-module-graph |
| """ |
| dep_variations = module.get("Variations") |
| dep_variation_os = "" |
| if dep_variations != None: |
| dep_variation_os = dep_variations.get("os") |
| return dep_variation_os == "windows" |
| |
| |
| def ignore_kind(kind): |
| return kind in IGNORED_KINDS or "defaults" in kind |