blob: ef228cb0486abcd79dbab44e1e68af896d39ac30 [file] [log] [blame]
Andrei Litvin7f358b62022-01-24 12:25:12 -05001#!/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
16import click
17import logging
Andrei Litvin7f358b62022-01-24 12:25:12 -050018import enum
Andrei Litvind1f0c552022-10-14 12:35:30 -040019import sys
Andrei Litvin7f358b62022-01-24 12:25:12 -050020
21try:
Feras Muki887822a2022-11-01 23:37:14 -040022 import coloredlogs
23 _has_coloredlogs = True
24except:
25 _has_coloredlogs = False
26
27try:
Andrei Litvin7f358b62022-01-24 12:25:12 -050028 from idl.matter_idl_parser import CreateParser
29except:
30 import os
Andrei Litvin7f358b62022-01-24 12:25:12 -050031 sys.path.append(os.path.abspath(os.path.dirname(__file__)))
32 from idl.matter_idl_parser import CreateParser
33
Andrei Litvin151a5f12022-01-25 18:06:35 -050034from idl.generators import FileSystemGeneratorStorage, GeneratorStorage
Andrei Litvin559c7d52022-10-21 13:38:11 -040035from idl.generators.registry import CodeGenerator, GENERATORS
Andrei Litvin7f358b62022-01-24 12:25:12 -050036
37
Andrei Litvin151a5f12022-01-25 18:06:35 -050038class ListGeneratedFilesStorage(GeneratorStorage):
39 """
Andrei Litvin3f68c3c2022-02-18 08:14:59 -050040 A storage that prints out file names that would have content in them.
Andrei Litvin151a5f12022-01-25 18:06:35 -050041 """
42
Andrei Litvind1f0c552022-10-14 12:35:30 -040043 def __init__(self):
44 super().__init__()
45
Andrei Litvin151a5f12022-01-25 18:06:35 -050046 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 Litvin7f358b62022-01-24 12:25:12 -050053# 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 Litvin7f358b62022-01-24 12:25:12 -050062
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 Litvin559c7d52022-10-21 13:38:11 -040072 type=click.Choice(GENERATORS.keys(), case_sensitive=False),
Andrei Litvin7f358b62022-01-24 12:25:12 -050073 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 Litvin151a5f12022-01-25 18:06:35 -050084@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 Litvind1f0c552022-10-14 12:35:30 -040089@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 Litvin7f358b62022-01-24 12:25:12 -050094@click.argument(
95 'idl_path',
96 type=click.Path(exists=True))
Andrei Litvind1f0c552022-10-14 12:35:30 -040097def main(log_level, generator, output_dir, dry_run, name_only, expected_outputs, idl_path):
Andrei Litvin7f358b62022-01-24 12:25:12 -050098 """
99 Parses MATTER IDL files (.matter) and performs SDK code generation
100 as set up by the program arguments.
101 """
Feras Muki887822a2022-11-01 23:37:14 -0400102 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 Litvin7f358b62022-01-24 12:25:12 -0500112 logging.info("Parsing idl from %s" % idl_path)
113 idl_tree = CreateParser().parse(open(idl_path, "rt").read())
114
Andrei Litvin151a5f12022-01-25 18:06:35 -0500115 if name_only:
116 storage = ListGeneratedFilesStorage()
117 else:
118 storage = FileSystemGeneratorStorage(output_dir)
119
Andrei Litvin7f358b62022-01-24 12:25:12 -0500120 logging.info("Running code generator %s" % generator)
Andrei Litvin559c7d52022-10-21 13:38:11 -0400121 generator = CodeGenerator.FromString(generator).Create(storage, idl=idl_tree)
Andrei Litvin7f358b62022-01-24 12:25:12 -0500122 generator.render(dry_run)
Andrei Litvind1f0c552022-10-14 12:35:30 -0400123
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 Litvin7f358b62022-01-24 12:25:12 -0500146 logging.info("Done")
147
148
149if __name__ == '__main__':
150 main()