Commit | Line | Data |
---|---|---|
dcdbb941 PP |
1 | # The MIT License (MIT) |
2 | # | |
4a90140d | 3 | # Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com> |
dcdbb941 | 4 | # |
1378f213 PP |
5 | # Permission is hereby granted, free of charge, to any person obtaining |
6 | # a copy of this software and associated documentation files (the | |
7 | # "Software"), to deal in the Software without restriction, including | |
8 | # without limitation the rights to use, copy, modify, merge, publish, | |
9 | # distribute, sublicense, and/or sell copies of the Software, and to | |
10 | # permit persons to whom the Software is furnished to do so, subject to | |
11 | # the following conditions: | |
dcdbb941 | 12 | # |
1378f213 PP |
13 | # The above copyright notice and this permission notice shall be |
14 | # included in all copies or substantial portions of the Software. | |
dcdbb941 | 15 | # |
1378f213 PP |
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
19 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
20 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
21 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
22 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
0f5c653b | 23 | |
3fcbfb51 | 24 | import termcolor |
e5aa0be3 | 25 | import os.path |
0f5c653b | 26 | import barectf |
4810b707 | 27 | import barectf.config_parse_common as barectf_config_parse_common |
ddfa8903 | 28 | import barectf.argpar as barectf_argpar |
2d55dc7d PP |
29 | from typing import Any, List, Iterable, NoReturn |
30 | import typing | |
31 | from barectf.typing import Index, Count | |
dcdbb941 PP |
32 | import sys |
33 | import os | |
dcdbb941 PP |
34 | |
35 | ||
4810b707 PP |
36 | # Colors and prints the error message `msg` and exits with status code |
37 | # 1. | |
2d55dc7d | 38 | def _print_error(msg: str) -> NoReturn: |
3fcbfb51 PP |
39 | termcolor.cprint('Error: ', 'red', end='', file=sys.stderr) |
40 | termcolor.cprint(msg, 'red', attrs=['bold'], file=sys.stderr) | |
e5aa0be3 | 41 | sys.exit(1) |
dcdbb941 PP |
42 | |
43 | ||
4810b707 PP |
44 | # Pretty-prints the barectf configuration error `exc` and exits with |
45 | # status code 1. | |
2d55dc7d | 46 | def _print_config_error(exc: barectf._ConfigurationParseError) -> NoReturn: |
4810b707 | 47 | # reverse: most precise message comes last |
97c18d79 | 48 | for ctx in reversed(exc.context): |
4810b707 PP |
49 | msg = '' |
50 | ||
97c18d79 PP |
51 | if ctx.message is not None: |
52 | msg = f' {ctx.message}' | |
6605ffed | 53 | |
4810b707 PP |
54 | color = 'red' |
55 | termcolor.cprint(f'{ctx.name}', color, attrs=['bold'], file=sys.stderr, end='') | |
56 | termcolor.cprint(':', color, file=sys.stderr, end='') | |
57 | termcolor.cprint(msg, color, file=sys.stderr) | |
e5aa0be3 PP |
58 | |
59 | sys.exit(1) | |
6b1365c7 PP |
60 | |
61 | ||
4810b707 | 62 | # Pretty-prints the unknown exception `exc`. |
2d55dc7d | 63 | def _print_unknown_exc(exc: Exception) -> NoReturn: |
4810b707 PP |
64 | import traceback |
65 | ||
66 | traceback.print_exc() | |
67 | _print_error(f'Unknown exception: {exc}') | |
dcdbb941 PP |
68 | |
69 | ||
ddfa8903 PP |
70 | # Finds and returns all the option items in `items` having the long name |
71 | # `long_name`. | |
2d55dc7d PP |
72 | def _find_opt_items(items: Iterable[barectf_argpar._Item], |
73 | long_name: str) -> List[barectf_argpar._OptItem]: | |
74 | ret_items: List[barectf_argpar._OptItem] = [] | |
ddfa8903 PP |
75 | |
76 | for item in items: | |
2d55dc7d PP |
77 | if type(item) is barectf_argpar._OptItem: |
78 | item = typing.cast(barectf_argpar._OptItem, item) | |
79 | ||
80 | if item.descr.long_name == long_name: | |
81 | ret_items.append(item) | |
ddfa8903 PP |
82 | |
83 | return ret_items | |
84 | ||
85 | ||
86 | # Returns: | |
87 | # | |
88 | # For an option item without an argument: | |
89 | # `True`. | |
90 | # | |
91 | # For an option item with an argument: | |
92 | # Its argument. | |
93 | # | |
94 | # Uses the last option item having the long name `long_name` found in | |
95 | # `items`. | |
96 | # | |
97 | # Returns `default` if there's no such option item. | |
2d55dc7d PP |
98 | def _opt_item_val(items: Iterable[barectf_argpar._Item], long_name: str, |
99 | default: Any = None) -> Any: | |
ddfa8903 PP |
100 | opt_items = _find_opt_items(items, long_name) |
101 | ||
102 | if len(opt_items) == 0: | |
103 | return default | |
104 | ||
105 | opt_item = opt_items[-1] | |
106 | ||
107 | if opt_item.descr.has_arg: | |
108 | return opt_item.arg_text | |
109 | ||
110 | return True | |
111 | ||
112 | ||
49419a0b | 113 | class _CliError(Exception): |
ddfa8903 PP |
114 | pass |
115 | ||
116 | ||
2d55dc7d | 117 | def _cfg_file_path_from_parse_res(parse_res: barectf_argpar._ParseRes) -> str: |
49419a0b | 118 | cfg_file_path = None |
ddfa8903 | 119 | |
49419a0b PP |
120 | for item in parse_res.items: |
121 | if type(item) is barectf_argpar._NonOptItem: | |
122 | if cfg_file_path is not None: | |
123 | raise _CliError('Multiple configuration file paths provided') | |
ddfa8903 | 124 | |
2d55dc7d | 125 | cfg_file_path = typing.cast(barectf_argpar._NonOptItem, item).text |
ddfa8903 | 126 | |
49419a0b PP |
127 | if cfg_file_path is None: |
128 | raise _CliError('Missing configuration file path') | |
ddfa8903 | 129 | |
49419a0b PP |
130 | if not os.path.isfile(cfg_file_path): |
131 | raise _CliError(f'`{cfg_file_path}` is not an existing, regular file') | |
ddfa8903 | 132 | |
f6c07d07 PP |
133 | return cfg_file_path |
134 | ||
135 | ||
136 | # Returns a `_CfgCmdCfg` object from the command-line parsing results | |
137 | # `parse_res`. | |
2d55dc7d | 138 | def _cfg_cmd_cfg_from_parse_res(parse_res: barectf_argpar._ParseRes) -> '_CfgCmdCfg': |
f6c07d07 PP |
139 | # check configuration file path |
140 | cfg_file_path = _cfg_file_path_from_parse_res(parse_res) | |
141 | ||
2d55dc7d PP |
142 | # inclusion directories (`--include-dir` option needs an argument) |
143 | inclusion_dirs = typing.cast(List[str], | |
144 | [item.arg_text for item in _find_opt_items(parse_res.items, 'include-dir')]) | |
ddfa8903 | 145 | |
49419a0b PP |
146 | for dir in inclusion_dirs: |
147 | if not os.path.isdir(dir): | |
148 | raise _CliError(f'`{dir}` is not an existing directory') | |
ddfa8903 | 149 | |
49419a0b | 150 | inclusion_dirs.append(os.getcwd()) |
ddfa8903 | 151 | |
49419a0b PP |
152 | # other options |
153 | ignore_inclusion_file_not_found = _opt_item_val(parse_res.items, 'ignore-include-not-found', | |
154 | False) | |
155 | ||
156 | return _CfgCmdCfg(cfg_file_path, inclusion_dirs, ignore_inclusion_file_not_found) | |
ddfa8903 PP |
157 | |
158 | ||
159 | def _print_gen_cmd_usage(): | |
160 | print('''Usage: barectf generate [--code-dir=DIR] [--headers-dir=DIR] | |
161 | [--metadata-dir=DIR] [--prefix=PREFIX] | |
162 | [--include-dir=DIR]... [--ignore-include-not-found] | |
49419a0b | 163 | CONFIG-FILE-PATH |
44591d11 | 164 | barectf generate --help |
ddfa8903 | 165 | |
fd3ac2ef PP |
166 | Generate the C source and CTF metadata stream files of a tracer from the |
167 | configuration file CONFIG-FILE-PATH. | |
168 | ||
ddfa8903 | 169 | Options: |
49419a0b PP |
170 | -c DIR, --code-dir=DIR Write C source files to DIR instead of the CWD |
171 | -H DIR, --headers-dir=DIR Write C header files to DIR instead of the CWD | |
44591d11 | 172 | -h, --help Show this help and quit |
ddfa8903 PP |
173 | --ignore-include-not-found Continue to process the configuration file when |
174 | included files are not found | |
175 | -I DIR, --include-dir=DIR Add DIR to the list of directories to be | |
176 | searched for inclusion files | |
49419a0b PP |
177 | -m DIR, --metadata-dir=DIR Write the metadata stream file to DIR instead of |
178 | the CWD | |
ddfa8903 PP |
179 | -p PREFIX, --prefix=PREFIX Set the configuration prefix to PREFIX''') |
180 | ||
181 | ||
49419a0b PP |
182 | # Returns a source and metadata stream file generating command object |
183 | # from the specific command-line arguments `orig_args`. | |
2d55dc7d | 184 | def _gen_cmd_cfg_from_args(orig_args: barectf_argpar.OrigArgs) -> '_GenCmd': |
ddfa8903 PP |
185 | # parse original arguments |
186 | opt_descrs = [ | |
187 | barectf_argpar.OptDescr('h', 'help'), | |
188 | barectf_argpar.OptDescr('c', 'code-dir', True), | |
189 | barectf_argpar.OptDescr('H', 'headers-dir', True), | |
190 | barectf_argpar.OptDescr('I', 'include-dir', True), | |
191 | barectf_argpar.OptDescr('m', 'metadata-dir', True), | |
192 | barectf_argpar.OptDescr('p', 'prefix', True), | |
193 | barectf_argpar.OptDescr(long_name='dump-config'), | |
194 | barectf_argpar.OptDescr(long_name='ignore-include-not-found'), | |
195 | ] | |
196 | res = barectf_argpar.parse(orig_args, opt_descrs) | |
197 | assert len(res.ingested_orig_args) == len(orig_args) | |
198 | ||
199 | # command help? | |
200 | if len(_find_opt_items(res.items, 'help')) > 0: | |
201 | _print_gen_cmd_usage() | |
202 | sys.exit() | |
203 | ||
49419a0b PP |
204 | # get common configuration file command CLI configuration |
205 | cfg_cmd_cfg = _cfg_cmd_cfg_from_parse_res(res) | |
ddfa8903 PP |
206 | |
207 | # directories | |
208 | c_source_dir = _opt_item_val(res.items, 'code-dir', os.getcwd()) | |
209 | c_header_dir = _opt_item_val(res.items, 'headers-dir', os.getcwd()) | |
210 | metadata_stream_dir = _opt_item_val(res.items, 'metadata-dir', os.getcwd()) | |
ddfa8903 | 211 | |
49419a0b | 212 | for dir in [c_source_dir, c_header_dir, metadata_stream_dir]: |
4810b707 | 213 | if not os.path.isdir(dir): |
ddfa8903 PP |
214 | raise _CliError(f'`{dir}` is not an existing directory') |
215 | ||
ddfa8903 | 216 | # other options |
ddfa8903 PP |
217 | dump_config = _opt_item_val(res.items, 'dump-config', False) |
218 | v2_prefix = _opt_item_val(res.items, 'prefix') | |
219 | ||
49419a0b PP |
220 | return _GenCmd(_GenCmdCfg(cfg_cmd_cfg.cfg_file_path, c_source_dir, c_header_dir, |
221 | metadata_stream_dir, cfg_cmd_cfg.inclusion_dirs, | |
222 | cfg_cmd_cfg.ignore_inclusion_file_not_found, dump_config, v2_prefix)) | |
223 | ||
224 | ||
f6c07d07 | 225 | def _show_effective_cfg_cmd_usage(): |
49419a0b PP |
226 | print('''Usage: barectf show-effective-configuration [--include-dir=DIR]... |
227 | [--ignore-include-not-found] | |
228 | [--indent-spaces=COUNT] CONFIG-FILE-PATH | |
44591d11 | 229 | barectf show-effective-configuration --help |
49419a0b | 230 | |
fd3ac2ef PP |
231 | Print the effective configuration file for a the configuration file |
232 | CONFIG-FILE-PATH. | |
233 | ||
49419a0b | 234 | Options: |
44591d11 | 235 | -h, --help Show this help and quit |
49419a0b PP |
236 | --ignore-include-not-found Continue to process the configuration file when |
237 | included files are not found | |
238 | -I DIR, --include-dir=DIR Add DIR to the list of directories to be | |
239 | searched for inclusion files | |
240 | --indent-spaces=COUNT Use COUNT spaces at a time to indent YAML lines | |
241 | instead of 2''') | |
242 | ||
243 | ||
244 | # Returns an effective configuration showing command object from the | |
245 | # specific command-line arguments `orig_args`. | |
2d55dc7d | 246 | def _show_effective_cfg_cfg_from_args(orig_args: barectf_argpar.OrigArgs) -> '_ShowEffectiveCfgCmd': |
49419a0b PP |
247 | # parse original arguments |
248 | opt_descrs = [ | |
249 | barectf_argpar.OptDescr('h', 'help'), | |
250 | barectf_argpar.OptDescr('I', 'include-dir', True), | |
251 | barectf_argpar.OptDescr(long_name='indent-spaces', has_arg=True), | |
252 | barectf_argpar.OptDescr(long_name='ignore-include-not-found'), | |
253 | ] | |
254 | res = barectf_argpar.parse(orig_args, opt_descrs) | |
255 | assert len(res.ingested_orig_args) == len(orig_args) | |
256 | ||
257 | # command help? | |
258 | if len(_find_opt_items(res.items, 'help')) > 0: | |
f6c07d07 | 259 | _show_effective_cfg_cmd_usage() |
49419a0b PP |
260 | sys.exit() |
261 | ||
262 | # get common configuration command CLI configuration | |
263 | cfg_cmd_cfg = _cfg_cmd_cfg_from_parse_res(res) | |
264 | ||
265 | # other options | |
266 | indent_space_count = _opt_item_val(res.items, 'indent-spaces', 2) | |
267 | ||
268 | try: | |
269 | indent_space_count = int(indent_space_count) | |
270 | except (ValueError, TypeError): | |
271 | raise _CliError(f'Invalid `--indent-spaces` option argument: `{indent_space_count}`') | |
272 | ||
273 | if indent_space_count < 1 or indent_space_count > 8: | |
274 | raise _CliError(f'Invalid `--indent-spaces` option argument (`{indent_space_count}`): expecting a value in [1, 8]') | |
275 | ||
276 | return _ShowEffectiveCfgCmd(_ShowEffectiveCfgCmdCfg(cfg_cmd_cfg.cfg_file_path, | |
277 | cfg_cmd_cfg.inclusion_dirs, | |
278 | cfg_cmd_cfg.ignore_inclusion_file_not_found, | |
2d55dc7d | 279 | Count(indent_space_count))) |
dcdbb941 | 280 | |
dcdbb941 | 281 | |
f6c07d07 | 282 | def _show_cfg_version_cmd_usage(): |
44591d11 PP |
283 | print('''Usage: barectf show-configuration-version CONFIG-FILE-PATH |
284 | barectf show-configuration-version --help | |
285 | ||
fd3ac2ef PP |
286 | Print the major version (2 or 3) of the configuration file CONFIG-FILE-PATH. |
287 | ||
44591d11 PP |
288 | Options: |
289 | -h, --help Show this help and quit''') | |
f6c07d07 PP |
290 | |
291 | ||
292 | # Returns a configuration version showing command object from the | |
293 | # specific command-line arguments `orig_args`. | |
2d55dc7d | 294 | def _show_cfg_version_cfg_from_args(orig_args: barectf_argpar.OrigArgs) -> '_ShowCfgVersionCmd': |
f6c07d07 PP |
295 | # parse original arguments |
296 | opt_descrs = [ | |
297 | barectf_argpar.OptDescr('h', 'help'), | |
298 | ] | |
299 | res = barectf_argpar.parse(orig_args, opt_descrs) | |
300 | assert len(res.ingested_orig_args) == len(orig_args) | |
301 | ||
302 | # command help? | |
303 | if len(_find_opt_items(res.items, 'help')) > 0: | |
304 | _show_cfg_version_cmd_usage() | |
305 | sys.exit() | |
306 | ||
307 | # check configuration file path | |
308 | cfg_file_path = _cfg_file_path_from_parse_res(res) | |
309 | ||
310 | return _ShowCfgVersionCmd(_ShowCfgVersionCmdCfg(cfg_file_path)) | |
311 | ||
312 | ||
ddfa8903 PP |
313 | def _print_general_usage(): |
314 | print('''Usage: barectf COMMAND COMMAND-ARGS | |
315 | barectf --help | |
316 | barectf --version | |
79750125 | 317 | |
ddfa8903 PP |
318 | General options: |
319 | -h, --help Show this help and quit | |
320 | -V, --version Show version and quit | |
321 | ||
322 | Available commands: | |
f6c07d07 PP |
323 | gen: |
324 | generate: | |
fd3ac2ef | 325 | Generate the C source and CTF metadata stream files of a tracer from a |
f6c07d07 PP |
326 | configuration file. |
327 | ||
328 | show-effective-configuration: | |
329 | show-effective-config: | |
330 | show-effective-cfg: | |
fd3ac2ef PP |
331 | Print the effective configuration file for a given configuration file and |
332 | inclusion directories. | |
f6c07d07 PP |
333 | |
334 | show-configuration-version: | |
335 | show-config-version: | |
336 | show-cfg-version | |
337 | Print the major version of a given configuration file. | |
ddfa8903 PP |
338 | |
339 | Run `barectf COMMAND --help` to show the help of COMMAND.''') | |
340 | ||
341 | ||
49419a0b PP |
342 | # Returns a command object from the command-line arguments `orig_args`. |
343 | # | |
344 | # All the `orig_args` elements are considered. | |
2d55dc7d | 345 | def _cmd_from_args(orig_args: barectf_argpar.OrigArgs) -> '_Cmd': |
ddfa8903 PP |
346 | # We use our `argpar` module here instead of Python's `argparse` |
347 | # because we need to support the two following use cases: | |
348 | # | |
349 | # $ barectf config.yaml | |
350 | # $ barectf generate config.yaml | |
351 | # | |
352 | # In other words, the default command is `generate` (for backward | |
353 | # compatibility reasons). The argument parser must not consider | |
354 | # `config.yaml` as being a command name. | |
355 | general_opt_descrs = [ | |
356 | barectf_argpar.OptDescr('V', 'version'), | |
357 | barectf_argpar.OptDescr('h', 'help'), | |
358 | ] | |
ddfa8903 PP |
359 | res = barectf_argpar.parse(orig_args, general_opt_descrs, False) |
360 | ||
361 | # find command name, collecting preceding (common) option items | |
49419a0b PP |
362 | cmd_from_args_funcs = { |
363 | 'generate': _gen_cmd_cfg_from_args, | |
364 | 'gen': _gen_cmd_cfg_from_args, | |
365 | 'show-effective-configuration': _show_effective_cfg_cfg_from_args, | |
366 | 'show-effective-config': _show_effective_cfg_cfg_from_args, | |
367 | 'show-effective-cfg': _show_effective_cfg_cfg_from_args, | |
f6c07d07 PP |
368 | 'show-configuration-version': _show_cfg_version_cfg_from_args, |
369 | 'show-config-version': _show_cfg_version_cfg_from_args, | |
370 | 'show-cfg-version': _show_cfg_version_cfg_from_args, | |
49419a0b | 371 | } |
2d55dc7d | 372 | general_opt_items: List[barectf_argpar._OptItem] = [] |
ddfa8903 | 373 | cmd_first_orig_arg_index = None |
49419a0b | 374 | cmd_from_args_func = None |
ddfa8903 PP |
375 | |
376 | for item in res.items: | |
377 | if type(item) is barectf_argpar._NonOptItem: | |
2d55dc7d | 378 | item = typing.cast(barectf_argpar._NonOptItem, item) |
49419a0b PP |
379 | cmd_from_args_func = cmd_from_args_funcs.get(item.text) |
380 | ||
381 | if cmd_from_args_func is None: | |
ddfa8903 | 382 | cmd_first_orig_arg_index = item.orig_arg_index |
49419a0b | 383 | else: |
2d55dc7d | 384 | cmd_first_orig_arg_index = Index(item.orig_arg_index + 1) |
ddfa8903 PP |
385 | |
386 | break | |
387 | else: | |
388 | assert type(item) is barectf_argpar._OptItem | |
2d55dc7d | 389 | general_opt_items.append(typing.cast(barectf_argpar._OptItem, item)) |
ddfa8903 PP |
390 | |
391 | # general help? | |
392 | if len(_find_opt_items(general_opt_items, 'help')) > 0: | |
393 | _print_general_usage() | |
394 | sys.exit() | |
395 | ||
396 | # version? | |
397 | if len(_find_opt_items(general_opt_items, 'version')) > 0: | |
398 | print(f'barectf {barectf.__version__}') | |
399 | sys.exit() | |
400 | ||
92230ce0 | 401 | # create command object |
ddfa8903 PP |
402 | cmd_orig_args = orig_args[cmd_first_orig_arg_index:] |
403 | ||
49419a0b | 404 | if cmd_from_args_func is None: |
ddfa8903 | 405 | # default `generate` command |
49419a0b | 406 | return _gen_cmd_cfg_from_args(cmd_orig_args) |
ddfa8903 | 407 | else: |
49419a0b PP |
408 | return cmd_from_args_func(cmd_orig_args) |
409 | ||
410 | ||
411 | class _CmdCfg: | |
412 | pass | |
413 | ||
414 | ||
415 | class _CfgCmdCfg(_CmdCfg): | |
2d55dc7d PP |
416 | def __init__(self, cfg_file_path: str, inclusion_dirs: List[str], |
417 | ignore_inclusion_file_not_found: bool): | |
49419a0b PP |
418 | self._cfg_file_path = cfg_file_path |
419 | self._inclusion_dirs = inclusion_dirs | |
420 | self._ignore_inclusion_file_not_found = ignore_inclusion_file_not_found | |
421 | ||
422 | @property | |
2d55dc7d | 423 | def cfg_file_path(self) -> str: |
49419a0b PP |
424 | return self._cfg_file_path |
425 | ||
426 | @property | |
2d55dc7d | 427 | def inclusion_dirs(self) -> List[str]: |
49419a0b PP |
428 | return self._inclusion_dirs |
429 | ||
430 | @property | |
2d55dc7d | 431 | def ignore_inclusion_file_not_found(self) -> bool: |
49419a0b PP |
432 | return self._ignore_inclusion_file_not_found |
433 | ||
434 | ||
435 | class _Cmd: | |
2d55dc7d | 436 | def __init__(self, cfg: _CmdCfg): |
49419a0b PP |
437 | self._cfg = cfg |
438 | ||
439 | @property | |
2d55dc7d | 440 | def cfg(self) -> _CmdCfg: |
49419a0b PP |
441 | return self._cfg |
442 | ||
443 | def exec(self): | |
444 | raise NotImplementedError | |
445 | ||
446 | ||
447 | class _GenCmdCfg(_CfgCmdCfg): | |
2d55dc7d PP |
448 | def __init__(self, cfg_file_path: str, c_source_dir: str, c_header_dir: str, |
449 | metadata_stream_dir: str, inclusion_dirs: List[str], | |
450 | ignore_inclusion_file_not_found: bool, dump_config: bool, v2_prefix: str): | |
49419a0b PP |
451 | super().__init__(cfg_file_path, inclusion_dirs, ignore_inclusion_file_not_found) |
452 | self._c_source_dir = c_source_dir | |
453 | self._c_header_dir = c_header_dir | |
454 | self._metadata_stream_dir = metadata_stream_dir | |
455 | self._dump_config = dump_config | |
456 | self._v2_prefix = v2_prefix | |
457 | ||
458 | @property | |
2d55dc7d | 459 | def c_source_dir(self) -> str: |
49419a0b PP |
460 | return self._c_source_dir |
461 | ||
462 | @property | |
2d55dc7d | 463 | def c_header_dir(self) -> str: |
49419a0b PP |
464 | return self._c_header_dir |
465 | ||
466 | @property | |
2d55dc7d | 467 | def metadata_stream_dir(self) -> str: |
49419a0b PP |
468 | return self._metadata_stream_dir |
469 | ||
470 | @property | |
2d55dc7d | 471 | def dump_config(self) -> bool: |
49419a0b PP |
472 | return self._dump_config |
473 | ||
474 | @property | |
2d55dc7d | 475 | def v2_prefix(self) -> str: |
49419a0b PP |
476 | return self._v2_prefix |
477 | ||
478 | ||
479 | # Source and metadata stream file generating command. | |
480 | class _GenCmd(_Cmd): | |
481 | def exec(self): | |
482 | # create configuration | |
483 | try: | |
484 | with open(self.cfg.cfg_file_path) as f: | |
485 | if self.cfg.dump_config: | |
486 | # print effective configuration file | |
487 | print(barectf.effective_configuration_file(f, True, self.cfg.inclusion_dirs, | |
488 | self.cfg.ignore_inclusion_file_not_found)) | |
489 | ||
490 | # barectf.configuration_from_file() reads the file again | |
491 | # below: rewind. | |
492 | f.seek(0) | |
493 | ||
494 | config = barectf.configuration_from_file(f, True, self.cfg.inclusion_dirs, | |
495 | self.cfg.ignore_inclusion_file_not_found) | |
496 | except barectf._ConfigurationParseError as exc: | |
497 | _print_config_error(exc) | |
498 | except Exception as exc: | |
499 | _print_unknown_exc(exc) | |
500 | ||
501 | if self.cfg.v2_prefix is not None: | |
502 | # Override prefixes. | |
503 | # | |
504 | # For historical reasons, the `--prefix` option applies the | |
505 | # barectf 2 configuration prefix rules. Therefore, get the | |
506 | # equivalent barectf 3 prefixes first. | |
507 | v3_prefixes = barectf_config_parse_common._v3_prefixes_from_v2_prefix(self.cfg.v2_prefix) | |
508 | cg_opts = config.options.code_generation_options | |
509 | cg_opts = barectf.ConfigurationCodeGenerationOptions(v3_prefixes.identifier, | |
510 | v3_prefixes.file_name, | |
e8f0d548 | 511 | cg_opts.default_data_stream_type, |
49419a0b PP |
512 | cg_opts.header_options, |
513 | cg_opts.clock_type_c_types) | |
514 | config = barectf.Configuration(config.trace, barectf.ConfigurationOptions(cg_opts)) | |
515 | ||
516 | # create a barectf code generator | |
517 | code_gen = barectf.CodeGenerator(config) | |
518 | ||
519 | def write_file(dir, file): | |
520 | with open(os.path.join(dir, file.name), 'w') as f: | |
521 | f.write(file.contents) | |
522 | ||
523 | def write_files(dir, files): | |
524 | for file in files: | |
525 | write_file(dir, file) | |
526 | ||
527 | try: | |
528 | # generate and write metadata stream file | |
529 | write_file(self.cfg.metadata_stream_dir, code_gen.generate_metadata_stream()) | |
530 | ||
531 | # generate and write C header files | |
532 | write_files(self.cfg.c_header_dir, code_gen.generate_c_headers()) | |
533 | ||
534 | # generate and write C source files | |
535 | write_files(self.cfg.c_source_dir, code_gen.generate_c_sources()) | |
536 | except Exception as exc: | |
537 | # We know `config` is valid, therefore the code generator cannot | |
538 | # fail for a reason known to barectf. | |
539 | _print_unknown_exc(exc) | |
540 | ||
541 | ||
542 | class _ShowEffectiveCfgCmdCfg(_CfgCmdCfg): | |
2d55dc7d PP |
543 | def __init__(self, cfg_file_path: str, inclusion_dirs: List[str], |
544 | ignore_inclusion_file_not_found: bool, indent_space_count: Count): | |
49419a0b PP |
545 | super().__init__(cfg_file_path, inclusion_dirs, ignore_inclusion_file_not_found) |
546 | self._indent_space_count = indent_space_count | |
547 | ||
548 | @property | |
2d55dc7d | 549 | def indent_space_count(self) -> Count: |
49419a0b PP |
550 | return self._indent_space_count |
551 | ||
552 | ||
553 | # Effective configuration showing command. | |
554 | class _ShowEffectiveCfgCmd(_Cmd): | |
555 | def exec(self): | |
556 | try: | |
557 | with open(self.cfg.cfg_file_path) as f: | |
558 | print(barectf.effective_configuration_file(f, True, self.cfg.inclusion_dirs, | |
559 | self.cfg.ignore_inclusion_file_not_found, | |
560 | self.cfg.indent_space_count)) | |
561 | except barectf._ConfigurationParseError as exc: | |
562 | _print_config_error(exc) | |
563 | except Exception as exc: | |
564 | _print_unknown_exc(exc) | |
dcdbb941 PP |
565 | |
566 | ||
f6c07d07 | 567 | class _ShowCfgVersionCmdCfg(_CmdCfg): |
2d55dc7d | 568 | def __init__(self, cfg_file_path: str): |
f6c07d07 PP |
569 | self._cfg_file_path = cfg_file_path |
570 | ||
571 | @property | |
2d55dc7d | 572 | def cfg_file_path(self) -> str: |
f6c07d07 PP |
573 | return self._cfg_file_path |
574 | ||
575 | ||
576 | class _ShowCfgVersionCmd(_Cmd): | |
577 | def exec(self): | |
578 | try: | |
579 | with open(self.cfg.cfg_file_path) as f: | |
580 | print(barectf.configuration_file_major_version(f)) | |
581 | except barectf._ConfigurationParseError as exc: | |
582 | _print_config_error(exc) | |
583 | except Exception as exc: | |
584 | _print_unknown_exc(exc) | |
585 | ||
586 | ||
c54d6f30 | 587 | def _run(): |
49419a0b | 588 | # create command from arguments |
ddfa8903 | 589 | try: |
49419a0b | 590 | cmd = _cmd_from_args(sys.argv[1:]) |
ddfa8903 PP |
591 | except barectf_argpar._Error as exc: |
592 | _print_error(f'Command-line: For argument `{exc.orig_arg}`: {exc.msg}') | |
593 | except _CliError as exc: | |
594 | _print_error(f'Command-line: {exc}') | |
595 | ||
49419a0b PP |
596 | # execute command |
597 | cmd.exec() |