| 1 | # The MIT License (MIT) |
| 2 | # |
| 3 | # Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com> |
| 4 | # |
| 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: |
| 12 | # |
| 13 | # The above copyright notice and this permission notice shall be |
| 14 | # included in all copies or substantial portions of the Software. |
| 15 | # |
| 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. |
| 23 | |
| 24 | import termcolor |
| 25 | import os.path |
| 26 | import barectf |
| 27 | import barectf.config_parse_common as barectf_config_parse_common |
| 28 | import barectf.argpar as barectf_argpar |
| 29 | from typing import Any, List, Iterable, NoReturn |
| 30 | import typing |
| 31 | from barectf.typing import Index, Count |
| 32 | import sys |
| 33 | import os |
| 34 | |
| 35 | |
| 36 | # Colors and prints the error message `msg` and exits with status code |
| 37 | # 1. |
| 38 | def _print_error(msg: str) -> NoReturn: |
| 39 | termcolor.cprint('Error: ', 'red', end='', file=sys.stderr) |
| 40 | termcolor.cprint(msg, 'red', attrs=['bold'], file=sys.stderr) |
| 41 | sys.exit(1) |
| 42 | |
| 43 | |
| 44 | # Pretty-prints the barectf configuration error `exc` and exits with |
| 45 | # status code 1. |
| 46 | def _print_config_error(exc: barectf._ConfigurationParseError) -> NoReturn: |
| 47 | # reverse: most precise message comes last |
| 48 | for ctx in reversed(exc.context): |
| 49 | msg = '' |
| 50 | |
| 51 | if ctx.message is not None: |
| 52 | msg = f' {ctx.message}' |
| 53 | |
| 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) |
| 58 | |
| 59 | sys.exit(1) |
| 60 | |
| 61 | |
| 62 | # Pretty-prints the unknown exception `exc`. |
| 63 | def _print_unknown_exc(exc: Exception) -> NoReturn: |
| 64 | import traceback |
| 65 | |
| 66 | traceback.print_exc() |
| 67 | _print_error(f'Unknown exception: {exc}') |
| 68 | |
| 69 | |
| 70 | # Finds and returns all the option items in `items` having the long name |
| 71 | # `long_name`. |
| 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] = [] |
| 75 | |
| 76 | for item in items: |
| 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) |
| 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. |
| 98 | def _opt_item_val(items: Iterable[barectf_argpar._Item], long_name: str, |
| 99 | default: Any = None) -> Any: |
| 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 | |
| 113 | class _CliError(Exception): |
| 114 | pass |
| 115 | |
| 116 | |
| 117 | def _cfg_file_path_from_parse_res(parse_res: barectf_argpar._ParseRes) -> str: |
| 118 | cfg_file_path = None |
| 119 | |
| 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') |
| 124 | |
| 125 | cfg_file_path = typing.cast(barectf_argpar._NonOptItem, item).text |
| 126 | |
| 127 | if cfg_file_path is None: |
| 128 | raise _CliError('Missing configuration file path') |
| 129 | |
| 130 | if not os.path.isfile(cfg_file_path): |
| 131 | raise _CliError(f'`{cfg_file_path}` is not an existing, regular file') |
| 132 | |
| 133 | return cfg_file_path |
| 134 | |
| 135 | |
| 136 | # Returns a `_CfgCmdCfg` object from the command-line parsing results |
| 137 | # `parse_res`. |
| 138 | def _cfg_cmd_cfg_from_parse_res(parse_res: barectf_argpar._ParseRes) -> '_CfgCmdCfg': |
| 139 | # check configuration file path |
| 140 | cfg_file_path = _cfg_file_path_from_parse_res(parse_res) |
| 141 | |
| 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')]) |
| 145 | |
| 146 | for dir in inclusion_dirs: |
| 147 | if not os.path.isdir(dir): |
| 148 | raise _CliError(f'`{dir}` is not an existing directory') |
| 149 | |
| 150 | inclusion_dirs.append(os.getcwd()) |
| 151 | |
| 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) |
| 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] |
| 163 | CONFIG-FILE-PATH |
| 164 | barectf generate --help |
| 165 | |
| 166 | Generate the C source and CTF metadata stream files of a tracer from the |
| 167 | configuration file CONFIG-FILE-PATH. |
| 168 | |
| 169 | Options: |
| 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 |
| 172 | -h, --help Show this help and quit |
| 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 |
| 177 | -m DIR, --metadata-dir=DIR Write the metadata stream file to DIR instead of |
| 178 | the CWD |
| 179 | -p PREFIX, --prefix=PREFIX Set the configuration prefix to PREFIX''') |
| 180 | |
| 181 | |
| 182 | # Returns a source and metadata stream file generating command object |
| 183 | # from the specific command-line arguments `orig_args`. |
| 184 | def _gen_cmd_cfg_from_args(orig_args: barectf_argpar.OrigArgs) -> '_GenCmd': |
| 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 | |
| 204 | # get common configuration file command CLI configuration |
| 205 | cfg_cmd_cfg = _cfg_cmd_cfg_from_parse_res(res) |
| 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()) |
| 211 | |
| 212 | for dir in [c_source_dir, c_header_dir, metadata_stream_dir]: |
| 213 | if not os.path.isdir(dir): |
| 214 | raise _CliError(f'`{dir}` is not an existing directory') |
| 215 | |
| 216 | # other options |
| 217 | dump_config = _opt_item_val(res.items, 'dump-config', False) |
| 218 | v2_prefix = _opt_item_val(res.items, 'prefix') |
| 219 | |
| 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 | |
| 225 | def _show_effective_cfg_cmd_usage(): |
| 226 | print('''Usage: barectf show-effective-configuration [--include-dir=DIR]... |
| 227 | [--ignore-include-not-found] |
| 228 | [--indent-spaces=COUNT] CONFIG-FILE-PATH |
| 229 | barectf show-effective-configuration --help |
| 230 | |
| 231 | Print the effective configuration file for a the configuration file |
| 232 | CONFIG-FILE-PATH. |
| 233 | |
| 234 | Options: |
| 235 | -h, --help Show this help and quit |
| 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`. |
| 246 | def _show_effective_cfg_cfg_from_args(orig_args: barectf_argpar.OrigArgs) -> '_ShowEffectiveCfgCmd': |
| 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: |
| 259 | _show_effective_cfg_cmd_usage() |
| 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, |
| 279 | Count(indent_space_count))) |
| 280 | |
| 281 | |
| 282 | def _show_cfg_version_cmd_usage(): |
| 283 | print('''Usage: barectf show-configuration-version CONFIG-FILE-PATH |
| 284 | barectf show-configuration-version --help |
| 285 | |
| 286 | Print the major version (2 or 3) of the configuration file CONFIG-FILE-PATH. |
| 287 | |
| 288 | Options: |
| 289 | -h, --help Show this help and quit''') |
| 290 | |
| 291 | |
| 292 | # Returns a configuration version showing command object from the |
| 293 | # specific command-line arguments `orig_args`. |
| 294 | def _show_cfg_version_cfg_from_args(orig_args: barectf_argpar.OrigArgs) -> '_ShowCfgVersionCmd': |
| 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 | |
| 313 | def _print_general_usage(): |
| 314 | print('''Usage: barectf COMMAND COMMAND-ARGS |
| 315 | barectf --help |
| 316 | barectf --version |
| 317 | |
| 318 | General options: |
| 319 | -h, --help Show this help and quit |
| 320 | -V, --version Show version and quit |
| 321 | |
| 322 | Available commands: |
| 323 | gen: |
| 324 | generate: |
| 325 | Generate the C source and CTF metadata stream files of a tracer from a |
| 326 | configuration file. |
| 327 | |
| 328 | show-effective-configuration: |
| 329 | show-effective-config: |
| 330 | show-effective-cfg: |
| 331 | Print the effective configuration file for a given configuration file and |
| 332 | inclusion directories. |
| 333 | |
| 334 | show-configuration-version: |
| 335 | show-config-version: |
| 336 | show-cfg-version |
| 337 | Print the major version of a given configuration file. |
| 338 | |
| 339 | Run `barectf COMMAND --help` to show the help of COMMAND.''') |
| 340 | |
| 341 | |
| 342 | # Returns a command object from the command-line arguments `orig_args`. |
| 343 | # |
| 344 | # All the `orig_args` elements are considered. |
| 345 | def _cmd_from_args(orig_args: barectf_argpar.OrigArgs) -> '_Cmd': |
| 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 | ] |
| 359 | res = barectf_argpar.parse(orig_args, general_opt_descrs, False) |
| 360 | |
| 361 | # find command name, collecting preceding (common) option items |
| 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, |
| 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, |
| 371 | } |
| 372 | general_opt_items: List[barectf_argpar._OptItem] = [] |
| 373 | cmd_first_orig_arg_index = None |
| 374 | cmd_from_args_func = None |
| 375 | |
| 376 | for item in res.items: |
| 377 | if type(item) is barectf_argpar._NonOptItem: |
| 378 | item = typing.cast(barectf_argpar._NonOptItem, item) |
| 379 | cmd_from_args_func = cmd_from_args_funcs.get(item.text) |
| 380 | |
| 381 | if cmd_from_args_func is None: |
| 382 | cmd_first_orig_arg_index = item.orig_arg_index |
| 383 | else: |
| 384 | cmd_first_orig_arg_index = Index(item.orig_arg_index + 1) |
| 385 | |
| 386 | break |
| 387 | else: |
| 388 | assert type(item) is barectf_argpar._OptItem |
| 389 | general_opt_items.append(typing.cast(barectf_argpar._OptItem, item)) |
| 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 | |
| 401 | # create command object |
| 402 | cmd_orig_args = orig_args[cmd_first_orig_arg_index:] |
| 403 | |
| 404 | if cmd_from_args_func is None: |
| 405 | # default `generate` command |
| 406 | return _gen_cmd_cfg_from_args(cmd_orig_args) |
| 407 | else: |
| 408 | return cmd_from_args_func(cmd_orig_args) |
| 409 | |
| 410 | |
| 411 | class _CmdCfg: |
| 412 | pass |
| 413 | |
| 414 | |
| 415 | class _CfgCmdCfg(_CmdCfg): |
| 416 | def __init__(self, cfg_file_path: str, inclusion_dirs: List[str], |
| 417 | ignore_inclusion_file_not_found: bool): |
| 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 |
| 423 | def cfg_file_path(self) -> str: |
| 424 | return self._cfg_file_path |
| 425 | |
| 426 | @property |
| 427 | def inclusion_dirs(self) -> List[str]: |
| 428 | return self._inclusion_dirs |
| 429 | |
| 430 | @property |
| 431 | def ignore_inclusion_file_not_found(self) -> bool: |
| 432 | return self._ignore_inclusion_file_not_found |
| 433 | |
| 434 | |
| 435 | class _Cmd: |
| 436 | def __init__(self, cfg: _CmdCfg): |
| 437 | self._cfg = cfg |
| 438 | |
| 439 | @property |
| 440 | def cfg(self) -> _CmdCfg: |
| 441 | return self._cfg |
| 442 | |
| 443 | def exec(self): |
| 444 | raise NotImplementedError |
| 445 | |
| 446 | |
| 447 | class _GenCmdCfg(_CfgCmdCfg): |
| 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): |
| 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 |
| 459 | def c_source_dir(self) -> str: |
| 460 | return self._c_source_dir |
| 461 | |
| 462 | @property |
| 463 | def c_header_dir(self) -> str: |
| 464 | return self._c_header_dir |
| 465 | |
| 466 | @property |
| 467 | def metadata_stream_dir(self) -> str: |
| 468 | return self._metadata_stream_dir |
| 469 | |
| 470 | @property |
| 471 | def dump_config(self) -> bool: |
| 472 | return self._dump_config |
| 473 | |
| 474 | @property |
| 475 | def v2_prefix(self) -> str: |
| 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, |
| 511 | cg_opts.default_data_stream_type, |
| 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): |
| 543 | def __init__(self, cfg_file_path: str, inclusion_dirs: List[str], |
| 544 | ignore_inclusion_file_not_found: bool, indent_space_count: Count): |
| 545 | super().__init__(cfg_file_path, inclusion_dirs, ignore_inclusion_file_not_found) |
| 546 | self._indent_space_count = indent_space_count |
| 547 | |
| 548 | @property |
| 549 | def indent_space_count(self) -> Count: |
| 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) |
| 565 | |
| 566 | |
| 567 | class _ShowCfgVersionCmdCfg(_CmdCfg): |
| 568 | def __init__(self, cfg_file_path: str): |
| 569 | self._cfg_file_path = cfg_file_path |
| 570 | |
| 571 | @property |
| 572 | def cfg_file_path(self) -> str: |
| 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 | |
| 587 | def _run(): |
| 588 | # create command from arguments |
| 589 | try: |
| 590 | cmd = _cmd_from_args(sys.argv[1:]) |
| 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 | |
| 596 | # execute command |
| 597 | cmd.exec() |