| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  | import logging | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from c_common.scriptutil import ( | 
					
						
							|  |  |  |     add_verbosity_cli, | 
					
						
							|  |  |  |     add_traceback_cli, | 
					
						
							|  |  |  |     add_kind_filtering_cli, | 
					
						
							|  |  |  |     add_files_cli, | 
					
						
							|  |  |  |     add_failure_filtering_cli, | 
					
						
							|  |  |  |     add_commands_cli, | 
					
						
							|  |  |  |     process_args_by_key, | 
					
						
							|  |  |  |     configure_logger, | 
					
						
							|  |  |  |     get_prog, | 
					
						
							|  |  |  |     main_for_filenames, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | from . import ( | 
					
						
							|  |  |  |     errors as _errors, | 
					
						
							|  |  |  |     get_preprocessor as _get_preprocessor, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FAIL = { | 
					
						
							|  |  |  |     'err': _errors.ErrorDirectiveError, | 
					
						
							|  |  |  |     'deps': _errors.MissingDependenciesError, | 
					
						
							|  |  |  |     'os': _errors.OSMismatchError, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | FAIL_DEFAULT = tuple(v for v in FAIL if v != 'os') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | logger = logging.getLogger(__name__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ################################## | 
					
						
							|  |  |  | # CLI helpers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def add_common_cli(parser, *, get_preprocessor=_get_preprocessor): | 
					
						
							|  |  |  |     parser.add_argument('--macros', action='append') | 
					
						
							|  |  |  |     parser.add_argument('--incldirs', action='append') | 
					
						
							|  |  |  |     parser.add_argument('--same', action='append') | 
					
						
							|  |  |  |     process_fail_arg = add_failure_filtering_cli(parser, FAIL) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-24 11:04:19 -07:00
										 |  |  |     def process_args(args, *, argv): | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         ns = vars(args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-01 11:20:20 -07:00
										 |  |  |         process_fail_arg(args, argv=argv) | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         ignore_exc = ns.pop('ignore_exc') | 
					
						
							|  |  |  |         # We later pass ignore_exc to _get_preprocessor(). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         args.get_file_preprocessor = get_preprocessor( | 
					
						
							|  |  |  |             file_macros=ns.pop('macros'), | 
					
						
							|  |  |  |             file_incldirs=ns.pop('incldirs'), | 
					
						
							|  |  |  |             file_same=ns.pop('same'), | 
					
						
							|  |  |  |             ignore_exc=ignore_exc, | 
					
						
							|  |  |  |             log_err=print, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     return process_args | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _iter_preprocessed(filename, *, | 
					
						
							|  |  |  |                        get_preprocessor, | 
					
						
							|  |  |  |                        match_kind=None, | 
					
						
							|  |  |  |                        pure=False, | 
					
						
							|  |  |  |                        ): | 
					
						
							|  |  |  |     preprocess = get_preprocessor(filename) | 
					
						
							|  |  |  |     for line in preprocess(tool=not pure) or (): | 
					
						
							|  |  |  |         if match_kind is not None and not match_kind(line.kind): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         yield line | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ####################################### | 
					
						
							|  |  |  | # the commands | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cli_preprocess(parser, excluded=None, **prepr_kwargs): | 
					
						
							|  |  |  |     parser.add_argument('--pure', action='store_true') | 
					
						
							|  |  |  |     parser.add_argument('--no-pure', dest='pure', action='store_const', const=False) | 
					
						
							|  |  |  |     process_kinds = add_kind_filtering_cli(parser) | 
					
						
							|  |  |  |     process_common = add_common_cli(parser, **prepr_kwargs) | 
					
						
							|  |  |  |     parser.add_argument('--raw', action='store_true') | 
					
						
							|  |  |  |     process_files = add_files_cli(parser, excluded=excluded) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [ | 
					
						
							|  |  |  |         process_kinds, | 
					
						
							|  |  |  |         process_common, | 
					
						
							|  |  |  |         process_files, | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def cmd_preprocess(filenames, *, | 
					
						
							|  |  |  |                    raw=False, | 
					
						
							|  |  |  |                    iter_filenames=None, | 
					
						
							|  |  |  |                    **kwargs | 
					
						
							|  |  |  |                    ): | 
					
						
							|  |  |  |     if 'get_file_preprocessor' not in kwargs: | 
					
						
							|  |  |  |         kwargs['get_file_preprocessor'] = _get_preprocessor() | 
					
						
							|  |  |  |     if raw: | 
					
						
							|  |  |  |         def show_file(filename, lines): | 
					
						
							|  |  |  |             for line in lines: | 
					
						
							|  |  |  |                 print(line) | 
					
						
							|  |  |  |                 #print(line.raw) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         def show_file(filename, lines): | 
					
						
							|  |  |  |             for line in lines: | 
					
						
							|  |  |  |                 linefile = '' | 
					
						
							|  |  |  |                 if line.filename != filename: | 
					
						
							|  |  |  |                     linefile = f' ({line.filename})' | 
					
						
							|  |  |  |                 text = line.data | 
					
						
							|  |  |  |                 if line.kind == 'comment': | 
					
						
							|  |  |  |                     text = '/* ' + line.data.splitlines()[0] | 
					
						
							|  |  |  |                     text += ' */' if '\n' in line.data else r'\n... */' | 
					
						
							|  |  |  |                 print(f' {line.lno:>4} {line.kind:10} | {text}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     filenames = main_for_filenames(filenames, iter_filenames) | 
					
						
							|  |  |  |     for filename in filenames: | 
					
						
							|  |  |  |         lines = _iter_preprocessed(filename, **kwargs) | 
					
						
							|  |  |  |         show_file(filename, lines) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cli_data(parser): | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def cmd_data(filenames, | 
					
						
							|  |  |  |              **kwargs | 
					
						
							|  |  |  |              ): | 
					
						
							|  |  |  |     # XXX | 
					
						
							|  |  |  |     raise NotImplementedError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COMMANDS = { | 
					
						
							|  |  |  |     'preprocess': ( | 
					
						
							|  |  |  |         'preprocess the given C source & header files', | 
					
						
							|  |  |  |         [_cli_preprocess], | 
					
						
							|  |  |  |         cmd_preprocess, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     'data': ( | 
					
						
							|  |  |  |         'check/manage local data (e.g. excludes, macros)', | 
					
						
							|  |  |  |         [_cli_data], | 
					
						
							|  |  |  |         cmd_data, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ####################################### | 
					
						
							|  |  |  | # the script | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_args(argv=sys.argv[1:], prog=sys.argv[0], *, | 
					
						
							|  |  |  |                subset='preprocess', | 
					
						
							|  |  |  |                excluded=None, | 
					
						
							|  |  |  |                **prepr_kwargs | 
					
						
							|  |  |  |                ): | 
					
						
							|  |  |  |     import argparse | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser( | 
					
						
							|  |  |  |         prog=prog or get_prog(), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     processors = add_commands_cli( | 
					
						
							|  |  |  |         parser, | 
					
						
							|  |  |  |         commands={k: v[1] for k, v in COMMANDS.items()}, | 
					
						
							|  |  |  |         commonspecs=[ | 
					
						
							|  |  |  |             add_verbosity_cli, | 
					
						
							|  |  |  |             add_traceback_cli, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         subset=subset, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args = parser.parse_args(argv) | 
					
						
							|  |  |  |     ns = vars(args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cmd = ns.pop('cmd') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     verbosity, traceback_cm = process_args_by_key( | 
					
						
							|  |  |  |         args, | 
					
						
							| 
									
										
										
										
											2020-12-24 11:04:19 -07:00
										 |  |  |         argv, | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         processors[cmd], | 
					
						
							|  |  |  |         ['verbosity', 'traceback_cm'], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return cmd, ns, verbosity, traceback_cm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(cmd, cmd_kwargs): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         run_cmd = COMMANDS[cmd][0] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         raise ValueError(f'unsupported cmd {cmd!r}') | 
					
						
							|  |  |  |     run_cmd(**cmd_kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     cmd, cmd_kwargs, verbosity, traceback_cm = parse_args() | 
					
						
							|  |  |  |     configure_logger(verbosity) | 
					
						
							|  |  |  |     with traceback_cm: | 
					
						
							|  |  |  |         main(cmd, cmd_kwargs) |