| # Copyright 2020 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import argparse |
| import os.path |
| import subprocess |
| import sys |
| from typing import Any, Mapping |
| |
| import wayland_protocol_c_arg_handling |
| import wayland_protocol_construction |
| import wayland_protocol_data_classes |
| import wayland_protocol_externals |
| import wayland_protocol_identifiers |
| |
| |
| def expand_template(template: str, context: Mapping[str, Any]) -> str: |
| """Expands the template using context, and returns the result""" |
| |
| # Loaded from third_party/jinja2 after a sys.path modification |
| import jinja2 |
| |
| env = jinja2.Environment( |
| loader=jinja2.FileSystemLoader(os.path.dirname(template)), |
| keep_trailing_newline=True, # newline-terminate generated files |
| lstrip_blocks=True, |
| trim_blocks=True) # so don't need {%- -%} everywhere |
| |
| # Additional global functions |
| env.globals['get_c_arg_for_server_request_arg'] = ( |
| wayland_protocol_c_arg_handling.get_c_arg_for_server_request_arg) |
| env.globals['get_c_arg_for_server_event_arg'] = ( |
| wayland_protocol_c_arg_handling.get_c_arg_for_server_event_arg) |
| env.globals['get_c_return_type_for_client_request'] = ( |
| wayland_protocol_c_arg_handling.get_c_return_type_for_client_request) |
| env.globals['get_c_arg_for_client_request_arg'] = ( |
| wayland_protocol_c_arg_handling.get_c_arg_for_client_request_arg) |
| env.globals['get_c_arg_for_client_event_arg'] = ( |
| wayland_protocol_c_arg_handling.get_c_arg_for_client_event_arg) |
| env.globals['get_construction_steps'] = ( |
| wayland_protocol_construction.get_construction_steps) |
| env.globals['get_destructor'] = ( |
| wayland_protocol_construction.get_destructor) |
| env.globals['get_external_interfaces_for_protocol'] = ( |
| wayland_protocol_externals.get_external_interfaces_for_protocol) |
| env.globals['get_minimum_version_to_construct'] = ( |
| wayland_protocol_construction.get_minimum_version_to_construct) |
| env.globals['get_versions_to_test_for_event_delivery'] = ( |
| wayland_protocol_construction.get_versions_to_test_for_event_delivery) |
| env.globals['is_global_interface'] = ( |
| wayland_protocol_construction.is_global_interface) |
| |
| # Additional filters for transforming text |
| env.filters['kebab'] = wayland_protocol_identifiers.kebab_case |
| env.filters['pascal'] = wayland_protocol_identifiers.pascal_case |
| |
| return env.get_template(os.path.basename(template)).render(context) |
| |
| |
| def clang_format_source_text(source_text: str, clang_format_path: str, |
| effective_filename: str) -> str: |
| """Runs clang-format on source_text and returns the result.""" |
| # clang-format the output, for better readability and for |
| # -Wmisleading-indentation. |
| return subprocess.run( |
| [clang_format_path, '--assume-filename', effective_filename], |
| input=source_text, |
| capture_output=True, |
| check=True, |
| text=True).stdout |
| |
| |
| def write_if_changed(source_text: str, output: str) -> str: |
| """Writes source_text to output, but only if different.""" |
| if os.path.exists(output): |
| with open(output, 'rt') as infile: |
| if infile.read() == source_text: |
| return |
| |
| with open(output, 'wt') as outfile: |
| outfile.write(source_text) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument('third_party_path') |
| parser.add_argument('clang_format_path') |
| parser.add_argument('template') |
| parser.add_argument('output') |
| parser.add_argument('protocols', nargs='+') |
| args = parser.parse_args() |
| |
| # Allows us to import jinga2 |
| sys.path.append(args.third_party_path) |
| |
| protocols = wayland_protocol_data_classes.Protocols.parse_xml_files( |
| args.protocols) |
| |
| if len(protocols.protocols) == 1: |
| expanded = expand_template(args.template, |
| {'protocol': protocols.protocols[0]}) |
| else: |
| expanded = expand_template(args.template, |
| {'protocols': protocols.protocols}) |
| |
| formatted = clang_format_source_text(expanded, args.clang_format_path, |
| args.output) |
| write_if_changed(formatted, args.output) |
| |
| |
| if __name__ == '__main__': |
| main() |