Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2022 Project CHIP Authors |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | import click |
| 17 | import logging |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 18 | import enum |
Andrei Litvin | d1f0c55 | 2022-10-14 12:35:30 -0400 | [diff] [blame] | 19 | import sys |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 20 | |
| 21 | try: |
Feras Muki | 887822a | 2022-11-01 23:37:14 -0400 | [diff] [blame] | 22 | import coloredlogs |
| 23 | _has_coloredlogs = True |
| 24 | except: |
| 25 | _has_coloredlogs = False |
| 26 | |
| 27 | try: |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 28 | from idl.matter_idl_parser import CreateParser |
| 29 | except: |
| 30 | import os |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 31 | sys.path.append(os.path.abspath(os.path.dirname(__file__))) |
| 32 | from idl.matter_idl_parser import CreateParser |
| 33 | |
Andrei Litvin | 151a5f1 | 2022-01-25 18:06:35 -0500 | [diff] [blame] | 34 | from idl.generators import FileSystemGeneratorStorage, GeneratorStorage |
Andrei Litvin | 559c7d5 | 2022-10-21 13:38:11 -0400 | [diff] [blame] | 35 | from idl.generators.registry import CodeGenerator, GENERATORS |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 36 | |
| 37 | |
Andrei Litvin | 151a5f1 | 2022-01-25 18:06:35 -0500 | [diff] [blame] | 38 | class ListGeneratedFilesStorage(GeneratorStorage): |
| 39 | """ |
Andrei Litvin | 3f68c3c | 2022-02-18 08:14:59 -0500 | [diff] [blame] | 40 | A storage that prints out file names that would have content in them. |
Andrei Litvin | 151a5f1 | 2022-01-25 18:06:35 -0500 | [diff] [blame] | 41 | """ |
| 42 | |
Andrei Litvin | d1f0c55 | 2022-10-14 12:35:30 -0400 | [diff] [blame] | 43 | def __init__(self): |
| 44 | super().__init__() |
| 45 | |
Andrei Litvin | 151a5f1 | 2022-01-25 18:06:35 -0500 | [diff] [blame] | 46 | def get_existing_data(self, relative_path: str): |
| 47 | return None # stdout has no pre-existing data |
| 48 | |
| 49 | def write_new_data(self, relative_path: str, content: str): |
| 50 | print(relative_path) |
| 51 | |
| 52 | |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 53 | # Supported log levels, mapping string values required for argument |
| 54 | # parsing into logging constants |
| 55 | __LOG_LEVELS__ = { |
| 56 | 'debug': logging.DEBUG, |
| 57 | 'info': logging.INFO, |
| 58 | 'warn': logging.WARN, |
| 59 | 'fatal': logging.FATAL, |
| 60 | } |
| 61 | |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 62 | |
| 63 | @click.command() |
| 64 | @click.option( |
| 65 | '--log-level', |
| 66 | default='INFO', |
| 67 | type=click.Choice(__LOG_LEVELS__.keys(), case_sensitive=False), |
| 68 | help='Determines the verbosity of script output') |
| 69 | @click.option( |
| 70 | '--generator', |
| 71 | default='JAVA', |
Andrei Litvin | 559c7d5 | 2022-10-21 13:38:11 -0400 | [diff] [blame] | 72 | type=click.Choice(GENERATORS.keys(), case_sensitive=False), |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 73 | help='What code generator to run') |
| 74 | @click.option( |
| 75 | '--output-dir', |
| 76 | type=click.Path(exists=False), |
| 77 | default=".", |
| 78 | help='Where to generate the code') |
| 79 | @click.option( |
| 80 | '--dry-run', |
| 81 | default=False, |
| 82 | is_flag=True, |
| 83 | help='If to actually generate') |
Andrei Litvin | 151a5f1 | 2022-01-25 18:06:35 -0500 | [diff] [blame] | 84 | @click.option( |
| 85 | '--name-only', |
| 86 | default=False, |
| 87 | is_flag=True, |
| 88 | help='Output just a list of file names that would be generated') |
Andrei Litvin | d1f0c55 | 2022-10-14 12:35:30 -0400 | [diff] [blame] | 89 | @click.option( |
| 90 | '--expected-outputs', |
| 91 | type=click.Path(exists=True), |
| 92 | default=None, |
| 93 | help='A file containing all expected outputs. Script will fail if outputs do not match') |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 94 | @click.argument( |
| 95 | 'idl_path', |
| 96 | type=click.Path(exists=True)) |
Andrei Litvin | d1f0c55 | 2022-10-14 12:35:30 -0400 | [diff] [blame] | 97 | def main(log_level, generator, output_dir, dry_run, name_only, expected_outputs, idl_path): |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 98 | """ |
| 99 | Parses MATTER IDL files (.matter) and performs SDK code generation |
| 100 | as set up by the program arguments. |
| 101 | """ |
Feras Muki | 887822a | 2022-11-01 23:37:14 -0400 | [diff] [blame] | 102 | if _has_coloredlogs: |
| 103 | coloredlogs.install(level=__LOG_LEVELS__[ |
| 104 | log_level], fmt='%(asctime)s %(levelname)-7s %(message)s') |
| 105 | else: |
| 106 | logging.basicConfig( |
| 107 | level=__LOG_LEVELS__[log_level], |
| 108 | format='%(asctime)s %(levelname)-7s %(message)s', |
| 109 | datefmt='%Y-%m-%d %H:%M:%S' |
| 110 | ) |
| 111 | |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 112 | logging.info("Parsing idl from %s" % idl_path) |
| 113 | idl_tree = CreateParser().parse(open(idl_path, "rt").read()) |
| 114 | |
Andrei Litvin | 151a5f1 | 2022-01-25 18:06:35 -0500 | [diff] [blame] | 115 | if name_only: |
| 116 | storage = ListGeneratedFilesStorage() |
| 117 | else: |
| 118 | storage = FileSystemGeneratorStorage(output_dir) |
| 119 | |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 120 | logging.info("Running code generator %s" % generator) |
Andrei Litvin | 559c7d5 | 2022-10-21 13:38:11 -0400 | [diff] [blame] | 121 | generator = CodeGenerator.FromString(generator).Create(storage, idl=idl_tree) |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 122 | generator.render(dry_run) |
Andrei Litvin | d1f0c55 | 2022-10-14 12:35:30 -0400 | [diff] [blame] | 123 | |
| 124 | if expected_outputs: |
| 125 | with open(expected_outputs, 'rt') as fin: |
| 126 | expected = set() |
| 127 | for l in fin.readlines(): |
| 128 | l = l.strip() |
| 129 | if l: |
| 130 | expected.add(l) |
| 131 | |
| 132 | if expected != storage.generated_paths: |
| 133 | logging.fatal("expected and generated files do not match.") |
| 134 | |
| 135 | extra = storage.generated_paths - expected |
| 136 | missing = expected - storage.generated_paths |
| 137 | |
| 138 | for name in extra: |
| 139 | logging.fatal(" '%s' was generated but not expected" % name) |
| 140 | |
| 141 | for name in missing: |
| 142 | logging.fatal(" '%s' was expected but not generated" % name) |
| 143 | |
| 144 | sys.exit(1) |
| 145 | |
Andrei Litvin | 7f358b6 | 2022-01-24 12:25:12 -0500 | [diff] [blame] | 146 | logging.info("Done") |
| 147 | |
| 148 | |
| 149 | if __name__ == '__main__': |
| 150 | main() |