168 lines
5.1 KiB
Python
Executable File
168 lines
5.1 KiB
Python
Executable File
#!/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.
|
|
"""A script to produce a csv report of all modules of a given type.
|
|
|
|
There is one output row per module of the input type, each column corresponds
|
|
to one of the fields of the _ModuleTypeInfo named tuple described below.
|
|
The script allows to ignore certain dependency edges based on the target module
|
|
name, or the dependency tag name.
|
|
|
|
Usage:
|
|
./bp2build-module-dep-infos.py -m <module type>
|
|
--ignore-by-name <modules to ignore>
|
|
|
|
"""
|
|
|
|
import argparse
|
|
import collections
|
|
import csv
|
|
import dependency_analysis
|
|
import sys
|
|
|
|
_ModuleTypeInfo = collections.namedtuple(
|
|
"_ModuleTypeInfo",
|
|
[
|
|
# map of module type to the set of properties used by modules
|
|
# of the given type in the dependency tree.
|
|
"type_to_properties",
|
|
# [java modules only] list of source file extensions used by this module.
|
|
"java_source_extensions",
|
|
],
|
|
)
|
|
|
|
def _get_java_source_extensions(module):
|
|
out = set()
|
|
if "Module" not in module:
|
|
return out
|
|
if "Java" not in module["Module"]:
|
|
return out
|
|
if "SourceExtensions" not in module["Module"]["Java"]:
|
|
return out
|
|
if module["Module"]["Java"]["SourceExtensions"]:
|
|
out.update(module["Module"]["Java"]["SourceExtensions"])
|
|
return out
|
|
|
|
|
|
def module_type_info_from_json(
|
|
module_graph, module_type, ignored_dep_names, ignore_java_auto_deps
|
|
):
|
|
"""Builds a map of module name to _ModuleTypeInfo for each module of module_type.
|
|
|
|
Dependency edges pointing to modules in ignored_dep_names are not followed.
|
|
"""
|
|
|
|
modules_of_type = set()
|
|
|
|
def filter_by_type(json):
|
|
if json["Type"] == module_type:
|
|
modules_of_type.add(json["Name"])
|
|
return True
|
|
return False
|
|
|
|
# dictionary of module name to _ModuleTypeInfo.
|
|
|
|
type_infos = {}
|
|
|
|
def update_infos(module, deps):
|
|
module_name = module["Name"]
|
|
info = type_infos.get(
|
|
module_name,
|
|
_ModuleTypeInfo(
|
|
java_source_extensions=set(),
|
|
type_to_properties=collections.defaultdict(set),
|
|
))
|
|
|
|
java_source_extensions = _get_java_source_extensions(module)
|
|
|
|
if module["Type"]:
|
|
info.type_to_properties[module["Type"]].update(
|
|
dependency_analysis.get_property_names(module))
|
|
|
|
for dep_name in deps:
|
|
for dep_type, dep_type_properties in type_infos[
|
|
dep_name].type_to_properties.items():
|
|
info.type_to_properties[dep_type].update(dep_type_properties)
|
|
java_source_extensions.update(
|
|
type_infos[dep_name].java_source_extensions)
|
|
|
|
info.java_source_extensions.update(java_source_extensions)
|
|
# for a module, collect all properties and java source extensions specified by
|
|
# transitive dependencies and the module itself
|
|
type_infos[module_name] = info
|
|
|
|
dependency_analysis.visit_json_module_graph_post_order(
|
|
module_graph, ignored_dep_names, ignore_java_auto_deps, filter_by_type, update_infos)
|
|
|
|
return {
|
|
name: info for name, info in type_infos.items() if name in modules_of_type
|
|
}
|
|
|
|
|
|
def _write_output(file_handle, type_infos):
|
|
writer = csv.writer(file_handle)
|
|
writer.writerow([
|
|
"module name",
|
|
"properties",
|
|
"java source extensions",
|
|
])
|
|
for module, module_type_info in type_infos.items():
|
|
writer.writerow([
|
|
module,
|
|
("[\"%s\"]" % '"\n"'.join([
|
|
"%s: %s" % (mtype, ",".join(properties)) for mtype, properties in
|
|
module_type_info.type_to_properties.items()
|
|
]) if len(module_type_info.type_to_properties) else "[]"),
|
|
("[\"%s\"]" % '", "'.join(module_type_info.java_source_extensions)
|
|
if len(module_type_info.java_source_extensions) else "[]"),
|
|
])
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--module-type", "-m", help="name of Soong module type.")
|
|
parser.add_argument(
|
|
"--ignore-by-name",
|
|
default="",
|
|
help=(
|
|
"Comma-separated list. When building the tree of transitive"
|
|
" dependencies, will not follow dependency edges pointing to module"
|
|
" names listed by this flag."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--ignore-java-auto-deps",
|
|
action="store_true",
|
|
help="whether to ignore automatically added java deps",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
module_type = args.module_type
|
|
ignore_by_name = args.ignore_by_name
|
|
|
|
module_graph = dependency_analysis.get_json_module_type_info(module_type)
|
|
type_infos = module_type_info_from_json(
|
|
module_graph,
|
|
module_type,
|
|
ignore_by_name.split(","),
|
|
args.ignore_java_auto_deps,
|
|
)
|
|
|
|
_write_output(sys.stdout, type_infos)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|