mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
	
	
		
			197 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			197 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								import logging
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from c_common.scriptutil import (
							 | 
						||
| 
								 | 
							
								    CLIArgSpec as Arg,
							 | 
						||
| 
								 | 
							
								    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)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_args(args):
							 | 
						||
| 
								 | 
							
								        ns = vars(args)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        process_fail_arg(args)
							 | 
						||
| 
								 | 
							
								        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,
							 | 
						||
| 
								 | 
							
								        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)
							 |