blob: 1fb51a5c9eb43ecd7143d5a2ddb9612e53686e9d [file] [log] [blame]
#!/usr/bin/python3
"""
List VTS tests for each HAL by parsing module-info.json.
Example usage:
# First, build modules-info.json
m -j "${ANDROID_PRODUCT_OUT#$ANDROID_BUILD_TOP/}/module-info.json"
# List with pretty-printed JSON. *IDL packages without a VTS module will show up
# as keys with empty lists.
./list_hals_vts.py | python3 -m json.tool
# List with CSV. *IDL packages without a VTS module will show up as a line with
# empty value in the VTS module column.
./list_hals_vts.py --csv
"""
import argparse
import collections
import csv
import io
import json
import os
import logging
import pathlib
import re
import sys
PATH_PACKAGE_PATTERN = re.compile(
r'^hardware/interfaces/(?P<path>(?:\w+/)*?)(?:aidl|(?P<version>\d+\.\d+))/.*')
class CriticalHandler(logging.StreamHandler):
def emit(self, record):
super(CriticalHandler, self).emit(record)
if record.levelno >= logging.CRITICAL:
sys.exit(1)
logger = logging.getLogger(__name__)
logger.addHandler(CriticalHandler())
def default_json():
out = os.environ.get('ANDROID_PRODUCT_OUT')
if not out: return None
return os.path.join(out, 'module-info.json')
def infer_package(path):
"""
Infer package from a relative path from build top where a VTS module lives.
:param path: a path like 'hardware/interfaces/vibrator/aidl/vts'
:return: The inferred *IDL package, e.g. 'android.hardware.vibrator'
>>> infer_package('hardware/interfaces/automotive/sv/1.0/vts/functional')
'android.hardware.automotive.sv@1.0'
>>> infer_package('hardware/interfaces/vibrator/aidl/vts')
'android.hardware.vibrator'
"""
mo = re.match(PATH_PACKAGE_PATTERN, path)
if not mo: return None
package = 'android.hardware.' + ('.'.join(pathlib.Path(mo.group('path')).parts))
if mo.group('version'):
package += '@' + mo.group('version')
return package
def load_modules_info(json_file):
"""
:param json_file: The path to modules-info.json
:return: a dictionary, where the keys are inferred *IDL package names, and
values are a list of VTS modules with that inferred package name.
"""
with open(json_file) as fp:
root = json.load(fp)
ret = collections.defaultdict(list)
for module_name, module_info in root.items():
if 'vts' not in module_info.get('compatibility_suites', []):
continue
for path in module_info.get('path', []):
inferred_package = infer_package(path)
if not inferred_package:
continue
ret[inferred_package].append(module_name)
return ret
def add_missing_idl(vts_modules):
top = os.environ.get("ANDROID_BUILD_TOP")
interfaces = None
if top:
interfaces = os.path.join(top, "hardware", "interfaces")
else:
logger.warning("Missing ANDROID_BUILD_TOP")
interfaces = "hardware/interfaces"
if not os.path.isdir(interfaces):
logger.error("Not adding missing *IDL modules because missing hardware/interfaces dir")
return
assert not interfaces.endswith(os.path.sep)
for root, dirs, files in os.walk(interfaces):
for dir in dirs:
full_dir = os.path.join(root, dir)
assert full_dir.startswith(interfaces)
top_rel_dir = os.path.join('hardware', 'interfaces', full_dir[len(interfaces) + 1:])
inferred_package = infer_package(top_rel_dir)
if inferred_package is None:
continue
if inferred_package not in vts_modules:
vts_modules[inferred_package] = []
def main():
parser = argparse.ArgumentParser(__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('json', metavar='module-info.json', default=default_json(), nargs='?')
parser.add_argument('--csv', action='store_true', help='Print CSV. If not specified print JSON.')
args = parser.parse_args()
if not args.json:
logger.critical('No module-info.json is specified or found.')
vts_modules = load_modules_info(args.json)
add_missing_idl(vts_modules)
if args.csv:
out = io.StringIO()
writer = csv.writer(out, )
writer.writerow(["package", "vts_module"])
for package, modules in vts_modules.items():
if not modules:
writer.writerow([package, ""])
for module in modules:
writer.writerow([package, module])
result = out.getvalue()
else:
result = json.dumps(vts_modules)
print(result)
if __name__ == '__main__':
main()