1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker# 4*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker# 8*6dbdd20aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker# 10*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker 16*6dbdd20aSAndroid Build Coastguard Workerimport argparse 17*6dbdd20aSAndroid Build Coastguard Workerimport os 18*6dbdd20aSAndroid Build Coastguard Workerimport sys 19*6dbdd20aSAndroid Build Coastguard Workerimport json 20*6dbdd20aSAndroid Build Coastguard Workerfrom collections import defaultdict 21*6dbdd20aSAndroid Build Coastguard Workerfrom typing import Dict 22*6dbdd20aSAndroid Build Coastguard Worker 23*6dbdd20aSAndroid Build Coastguard WorkerROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 24*6dbdd20aSAndroid Build Coastguard Workersys.path.append(os.path.join(ROOT_DIR)) 25*6dbdd20aSAndroid Build Coastguard Worker 26*6dbdd20aSAndroid Build Coastguard Workerfrom python.generators.sql_processing.docs_parse import parse_file 27*6dbdd20aSAndroid Build Coastguard Worker 28*6dbdd20aSAndroid Build Coastguard Worker 29*6dbdd20aSAndroid Build Coastguard Workerdef _summary_desc(s: str) -> str: 30*6dbdd20aSAndroid Build Coastguard Worker return s.split('. ')[0].replace('\n', ' ') 31*6dbdd20aSAndroid Build Coastguard Worker 32*6dbdd20aSAndroid Build Coastguard Worker 33*6dbdd20aSAndroid Build Coastguard Workerdef main(): 34*6dbdd20aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 35*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument('--json-out', required=True) 36*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument('--input-list-file') 37*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument('--minify') 38*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument('sql_files', nargs='*') 39*6dbdd20aSAndroid Build Coastguard Worker args = parser.parse_args() 40*6dbdd20aSAndroid Build Coastguard Worker 41*6dbdd20aSAndroid Build Coastguard Worker if args.input_list_file and args.sql_files: 42*6dbdd20aSAndroid Build Coastguard Worker print("Only one of --input-list-file and list of SQL files expected") 43*6dbdd20aSAndroid Build Coastguard Worker return 1 44*6dbdd20aSAndroid Build Coastguard Worker 45*6dbdd20aSAndroid Build Coastguard Worker sql_files = [] 46*6dbdd20aSAndroid Build Coastguard Worker if args.input_list_file: 47*6dbdd20aSAndroid Build Coastguard Worker with open(args.input_list_file, 'r') as input_list_file: 48*6dbdd20aSAndroid Build Coastguard Worker for line in input_list_file.read().splitlines(): 49*6dbdd20aSAndroid Build Coastguard Worker sql_files.append(line) 50*6dbdd20aSAndroid Build Coastguard Worker else: 51*6dbdd20aSAndroid Build Coastguard Worker sql_files = args.sql_files 52*6dbdd20aSAndroid Build Coastguard Worker 53*6dbdd20aSAndroid Build Coastguard Worker # Unfortunately we cannot pass this in as an arg as soong does not provide 54*6dbdd20aSAndroid Build Coastguard Worker # us a way to get the path to the Perfetto source directory. This fails on 55*6dbdd20aSAndroid Build Coastguard Worker # empty path but it's a price worth paying to have to use gross hacks in 56*6dbdd20aSAndroid Build Coastguard Worker # Soong. 57*6dbdd20aSAndroid Build Coastguard Worker root_dir = os.path.commonpath(sql_files) 58*6dbdd20aSAndroid Build Coastguard Worker 59*6dbdd20aSAndroid Build Coastguard Worker # Extract the SQL output from each file. 60*6dbdd20aSAndroid Build Coastguard Worker sql_outputs: Dict[str, str] = {} 61*6dbdd20aSAndroid Build Coastguard Worker for file_name in sql_files: 62*6dbdd20aSAndroid Build Coastguard Worker with open(file_name, 'r') as f: 63*6dbdd20aSAndroid Build Coastguard Worker relpath = os.path.relpath(file_name, root_dir) 64*6dbdd20aSAndroid Build Coastguard Worker 65*6dbdd20aSAndroid Build Coastguard Worker # We've had bugs (e.g. b/264711057) when Soong's common path logic breaks 66*6dbdd20aSAndroid Build Coastguard Worker # and ends up with a bunch of ../ prefixing the path: disallow any ../ 67*6dbdd20aSAndroid Build Coastguard Worker # as this should never be a valid in our C++ output. 68*6dbdd20aSAndroid Build Coastguard Worker assert '../' not in relpath 69*6dbdd20aSAndroid Build Coastguard Worker 70*6dbdd20aSAndroid Build Coastguard Worker sql_outputs[relpath] = f.read() 71*6dbdd20aSAndroid Build Coastguard Worker 72*6dbdd20aSAndroid Build Coastguard Worker packages = defaultdict(list) 73*6dbdd20aSAndroid Build Coastguard Worker # Add documentation from each file 74*6dbdd20aSAndroid Build Coastguard Worker for path, sql in sql_outputs.items(): 75*6dbdd20aSAndroid Build Coastguard Worker package_name = path.split("/")[0] 76*6dbdd20aSAndroid Build Coastguard Worker module_name = path.split(".sql")[0].replace("/", ".") 77*6dbdd20aSAndroid Build Coastguard Worker 78*6dbdd20aSAndroid Build Coastguard Worker docs = parse_file(path, sql) 79*6dbdd20aSAndroid Build Coastguard Worker 80*6dbdd20aSAndroid Build Coastguard Worker # Some modules (i.e `deprecated`) should not generate docs. 81*6dbdd20aSAndroid Build Coastguard Worker if not docs: 82*6dbdd20aSAndroid Build Coastguard Worker continue 83*6dbdd20aSAndroid Build Coastguard Worker 84*6dbdd20aSAndroid Build Coastguard Worker if len(docs.errors) > 0: 85*6dbdd20aSAndroid Build Coastguard Worker for e in docs.errors: 86*6dbdd20aSAndroid Build Coastguard Worker print(e) 87*6dbdd20aSAndroid Build Coastguard Worker return 1 88*6dbdd20aSAndroid Build Coastguard Worker 89*6dbdd20aSAndroid Build Coastguard Worker module_dict = { 90*6dbdd20aSAndroid Build Coastguard Worker 'module_name': 91*6dbdd20aSAndroid Build Coastguard Worker module_name, 92*6dbdd20aSAndroid Build Coastguard Worker 'data_objects': [{ 93*6dbdd20aSAndroid Build Coastguard Worker 'name': 94*6dbdd20aSAndroid Build Coastguard Worker table.name, 95*6dbdd20aSAndroid Build Coastguard Worker 'desc': 96*6dbdd20aSAndroid Build Coastguard Worker table.desc, 97*6dbdd20aSAndroid Build Coastguard Worker 'summary_desc': 98*6dbdd20aSAndroid Build Coastguard Worker _summary_desc(table.desc), 99*6dbdd20aSAndroid Build Coastguard Worker 'type': 100*6dbdd20aSAndroid Build Coastguard Worker table.type, 101*6dbdd20aSAndroid Build Coastguard Worker 'cols': [{ 102*6dbdd20aSAndroid Build Coastguard Worker 'name': col_name, 103*6dbdd20aSAndroid Build Coastguard Worker 'type': col.long_type, 104*6dbdd20aSAndroid Build Coastguard Worker 'desc': col.description 105*6dbdd20aSAndroid Build Coastguard Worker } for (col_name, col) in table.cols.items()] 106*6dbdd20aSAndroid Build Coastguard Worker } for table in docs.table_views], 107*6dbdd20aSAndroid Build Coastguard Worker 'functions': [{ 108*6dbdd20aSAndroid Build Coastguard Worker 'name': function.name, 109*6dbdd20aSAndroid Build Coastguard Worker 'desc': function.desc, 110*6dbdd20aSAndroid Build Coastguard Worker 'summary_desc': _summary_desc(function.desc), 111*6dbdd20aSAndroid Build Coastguard Worker 'args': [{ 112*6dbdd20aSAndroid Build Coastguard Worker 'name': arg_name, 113*6dbdd20aSAndroid Build Coastguard Worker 'type': arg.long_type, 114*6dbdd20aSAndroid Build Coastguard Worker 'desc': arg.description, 115*6dbdd20aSAndroid Build Coastguard Worker } for (arg_name, arg) in function.args.items()], 116*6dbdd20aSAndroid Build Coastguard Worker 'return_type': function.return_type, 117*6dbdd20aSAndroid Build Coastguard Worker 'return_desc': function.return_desc, 118*6dbdd20aSAndroid Build Coastguard Worker } for function in docs.functions], 119*6dbdd20aSAndroid Build Coastguard Worker 'table_functions': [{ 120*6dbdd20aSAndroid Build Coastguard Worker 'name': 121*6dbdd20aSAndroid Build Coastguard Worker function.name, 122*6dbdd20aSAndroid Build Coastguard Worker 'desc': 123*6dbdd20aSAndroid Build Coastguard Worker function.desc, 124*6dbdd20aSAndroid Build Coastguard Worker 'summary_desc': 125*6dbdd20aSAndroid Build Coastguard Worker _summary_desc(function.desc), 126*6dbdd20aSAndroid Build Coastguard Worker 'args': [{ 127*6dbdd20aSAndroid Build Coastguard Worker 'name': arg_name, 128*6dbdd20aSAndroid Build Coastguard Worker 'type': arg.long_type, 129*6dbdd20aSAndroid Build Coastguard Worker 'desc': arg.description, 130*6dbdd20aSAndroid Build Coastguard Worker } for (arg_name, arg) in function.args.items()], 131*6dbdd20aSAndroid Build Coastguard Worker 'cols': [{ 132*6dbdd20aSAndroid Build Coastguard Worker 'name': col_name, 133*6dbdd20aSAndroid Build Coastguard Worker 'type': col.long_type, 134*6dbdd20aSAndroid Build Coastguard Worker 'desc': col.description 135*6dbdd20aSAndroid Build Coastguard Worker } for (col_name, col) in function.cols.items()] 136*6dbdd20aSAndroid Build Coastguard Worker } for function in docs.table_functions], 137*6dbdd20aSAndroid Build Coastguard Worker 'macros': [{ 138*6dbdd20aSAndroid Build Coastguard Worker 'name': 139*6dbdd20aSAndroid Build Coastguard Worker macro.name, 140*6dbdd20aSAndroid Build Coastguard Worker 'desc': 141*6dbdd20aSAndroid Build Coastguard Worker macro.desc, 142*6dbdd20aSAndroid Build Coastguard Worker 'summary_desc': 143*6dbdd20aSAndroid Build Coastguard Worker _summary_desc(macro.desc), 144*6dbdd20aSAndroid Build Coastguard Worker 'return_desc': 145*6dbdd20aSAndroid Build Coastguard Worker macro.return_desc, 146*6dbdd20aSAndroid Build Coastguard Worker 'return_type': 147*6dbdd20aSAndroid Build Coastguard Worker macro.return_type, 148*6dbdd20aSAndroid Build Coastguard Worker 'args': [{ 149*6dbdd20aSAndroid Build Coastguard Worker 'name': arg_name, 150*6dbdd20aSAndroid Build Coastguard Worker 'type': arg.long_type, 151*6dbdd20aSAndroid Build Coastguard Worker 'desc': arg.description, 152*6dbdd20aSAndroid Build Coastguard Worker } for (arg_name, arg) in macro.args.items()], 153*6dbdd20aSAndroid Build Coastguard Worker } for macro in docs.macros], 154*6dbdd20aSAndroid Build Coastguard Worker } 155*6dbdd20aSAndroid Build Coastguard Worker packages[package_name].append(module_dict) 156*6dbdd20aSAndroid Build Coastguard Worker 157*6dbdd20aSAndroid Build Coastguard Worker packages_list = [{ 158*6dbdd20aSAndroid Build Coastguard Worker "name": name, 159*6dbdd20aSAndroid Build Coastguard Worker "modules": modules 160*6dbdd20aSAndroid Build Coastguard Worker } for name, modules in packages.items()] 161*6dbdd20aSAndroid Build Coastguard Worker 162*6dbdd20aSAndroid Build Coastguard Worker with open(args.json_out, 'w+') as f: 163*6dbdd20aSAndroid Build Coastguard Worker json.dump(packages_list, f, indent=None if args.minify else 4) 164*6dbdd20aSAndroid Build Coastguard Worker 165*6dbdd20aSAndroid Build Coastguard Worker return 0 166*6dbdd20aSAndroid Build Coastguard Worker 167*6dbdd20aSAndroid Build Coastguard Worker 168*6dbdd20aSAndroid Build Coastguard Workerif __name__ == '__main__': 169*6dbdd20aSAndroid Build Coastguard Worker sys.exit(main()) 170