blob: 8ae6044fd0cfa2ec64d823372ad46a618656e9c5 [file] [log] [blame]
#!/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.
import argparse
import os
import sys
import json
from collections import defaultdict
from typing import Dict
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(os.path.join(ROOT_DIR))
from python.generators.sql_processing.docs_parse import parse_file
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--json-out', required=True)
parser.add_argument('--input-list-file')
parser.add_argument('sql_files', nargs='*')
args = parser.parse_args()
if args.input_list_file and args.sql_files:
print("Only one of --input-list-file and list of SQL files expected")
return 1
sql_files = []
if args.input_list_file:
with open(args.input_list_file, 'r') as input_list_file:
for line in input_list_file.read().splitlines():
sql_files.append(line)
else:
sql_files = args.sql_files
# Unfortunately we cannot pass this in as an arg as soong does not provide
# us a way to get the path to the Perfetto source directory. This fails on
# empty path but it's a price worth paying to have to use gross hacks in
# Soong.
root_dir = os.path.commonpath(sql_files)
# Extract the SQL output from each file.
sql_outputs: Dict[str, str] = {}
for file_name in sql_files:
with open(file_name, 'r') as f:
relpath = os.path.relpath(file_name, root_dir)
# We've had bugs (e.g. b/264711057) when Soong's common path logic breaks
# and ends up with a bunch of ../ prefixing the path: disallow any ../
# as this should never be a valid in our C++ output.
assert '../' not in relpath
sql_outputs[relpath] = f.read()
modules = defaultdict(list)
# Add documentation from each file
for path, sql in sql_outputs.items():
module_name = path.split("/")[0]
import_key = path.split(".sql")[0].replace("/", ".")
docs = parse_file(path, sql)
# Some modules (i.e `deprecated`) should not generate docs.
if not docs:
continue
if len(docs.errors) > 0:
for e in docs.errors:
print(e)
return 1
file_dict = {
'import_key':
import_key,
'imports': [{
'name': table.name,
'desc': table.desc,
'summary_desc': table.desc.split('\n\n')[0].replace('\n', ' '),
'type': table.type,
'cols': {
col_name: {
'type': col.type,
'desc': col.description,
} for (col_name, col) in table.cols.items()
},
} for table in docs.table_views],
'functions': [{
'name': function.name,
'desc': function.desc,
'summary_desc': function.desc.split('\n\n')[0].replace('\n', ' '),
'args': {
arg_name: {
'type': arg.type,
'desc': arg.description,
} for (arg_name, arg) in function.args.items()
},
'return_type': function.return_type,
'return_desc': function.return_desc,
} for function in docs.functions],
'table_functions': [{
'name': function.name,
'desc': function.desc,
'summary_desc': function.desc.split('\n\n')[0].replace('\n', ' '),
'args': {
arg_name: {
'type': arg.type,
'desc': arg.description,
} for (arg_name, arg) in function.args.items()
},
'cols': {
col_name: {
'type': col.type,
'desc': col.description,
} for (col_name, col) in function.cols.items()
},
} for function in docs.table_functions],
'macros': [{
'name': macro.name,
'desc': macro.desc,
'summary_desc': macro.desc.split('\n\n')[0].replace('\n', ' '),
'return_desc': macro.return_desc,
'return_type': macro.return_type,
'args': {
arg_name: {
'type': arg.type,
'desc': arg.description,
} for (arg_name, arg) in macro.args.items()
},
} for macro in docs.macros],
}
modules[module_name].append(file_dict)
with open(args.json_out, 'w+') as f:
json.dump(modules, f, indent=4)
return 0
if __name__ == '__main__':
sys.exit(main())