17db96d56Sopenharmony_ciimport io
27db96d56Sopenharmony_ciimport logging
37db96d56Sopenharmony_ciimport os
47db96d56Sopenharmony_ciimport os.path
57db96d56Sopenharmony_ciimport re
67db96d56Sopenharmony_ciimport sys
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_cifrom c_common import fsutil
97db96d56Sopenharmony_cifrom c_common.logging import VERBOSITY, Printer
107db96d56Sopenharmony_cifrom c_common.scriptutil import (
117db96d56Sopenharmony_ci    add_verbosity_cli,
127db96d56Sopenharmony_ci    add_traceback_cli,
137db96d56Sopenharmony_ci    add_sepval_cli,
147db96d56Sopenharmony_ci    add_progress_cli,
157db96d56Sopenharmony_ci    add_files_cli,
167db96d56Sopenharmony_ci    add_commands_cli,
177db96d56Sopenharmony_ci    process_args_by_key,
187db96d56Sopenharmony_ci    configure_logger,
197db96d56Sopenharmony_ci    get_prog,
207db96d56Sopenharmony_ci    filter_filenames,
217db96d56Sopenharmony_ci    iter_marks,
227db96d56Sopenharmony_ci)
237db96d56Sopenharmony_cifrom c_parser.info import KIND
247db96d56Sopenharmony_cifrom c_parser.match import is_type_decl
257db96d56Sopenharmony_cifrom .match import filter_forward
267db96d56Sopenharmony_cifrom . import (
277db96d56Sopenharmony_ci    analyze as _analyze,
287db96d56Sopenharmony_ci    datafiles as _datafiles,
297db96d56Sopenharmony_ci    check_all as _check_all,
307db96d56Sopenharmony_ci)
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ciKINDS = [
347db96d56Sopenharmony_ci    KIND.TYPEDEF,
357db96d56Sopenharmony_ci    KIND.STRUCT,
367db96d56Sopenharmony_ci    KIND.UNION,
377db96d56Sopenharmony_ci    KIND.ENUM,
387db96d56Sopenharmony_ci    KIND.FUNCTION,
397db96d56Sopenharmony_ci    KIND.VARIABLE,
407db96d56Sopenharmony_ci    KIND.STATEMENT,
417db96d56Sopenharmony_ci]
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_cilogger = logging.getLogger(__name__)
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci#######################################
477db96d56Sopenharmony_ci# table helpers
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ciTABLE_SECTIONS = {
507db96d56Sopenharmony_ci    'types': (
517db96d56Sopenharmony_ci        ['kind', 'name', 'data', 'file'],
527db96d56Sopenharmony_ci        KIND.is_type_decl,
537db96d56Sopenharmony_ci        (lambda v: (v.kind.value, v.filename or '', v.name)),
547db96d56Sopenharmony_ci    ),
557db96d56Sopenharmony_ci    'typedefs': 'types',
567db96d56Sopenharmony_ci    'structs': 'types',
577db96d56Sopenharmony_ci    'unions': 'types',
587db96d56Sopenharmony_ci    'enums': 'types',
597db96d56Sopenharmony_ci    'functions': (
607db96d56Sopenharmony_ci        ['name', 'data', 'file'],
617db96d56Sopenharmony_ci        (lambda kind: kind is KIND.FUNCTION),
627db96d56Sopenharmony_ci        (lambda v: (v.filename or '', v.name)),
637db96d56Sopenharmony_ci    ),
647db96d56Sopenharmony_ci    'variables': (
657db96d56Sopenharmony_ci        ['name', 'parent', 'data', 'file'],
667db96d56Sopenharmony_ci        (lambda kind: kind is KIND.VARIABLE),
677db96d56Sopenharmony_ci        (lambda v: (v.filename or '', str(v.parent) if v.parent else '', v.name)),
687db96d56Sopenharmony_ci    ),
697db96d56Sopenharmony_ci    'statements': (
707db96d56Sopenharmony_ci        ['file', 'parent', 'data'],
717db96d56Sopenharmony_ci        (lambda kind: kind is KIND.STATEMENT),
727db96d56Sopenharmony_ci        (lambda v: (v.filename or '', str(v.parent) if v.parent else '', v.name)),
737db96d56Sopenharmony_ci    ),
747db96d56Sopenharmony_ci    KIND.TYPEDEF: 'typedefs',
757db96d56Sopenharmony_ci    KIND.STRUCT: 'structs',
767db96d56Sopenharmony_ci    KIND.UNION: 'unions',
777db96d56Sopenharmony_ci    KIND.ENUM: 'enums',
787db96d56Sopenharmony_ci    KIND.FUNCTION: 'functions',
797db96d56Sopenharmony_ci    KIND.VARIABLE: 'variables',
807db96d56Sopenharmony_ci    KIND.STATEMENT: 'statements',
817db96d56Sopenharmony_ci}
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_cidef _render_table(items, columns, relroot=None):
857db96d56Sopenharmony_ci    # XXX improve this
867db96d56Sopenharmony_ci    header = '\t'.join(columns)
877db96d56Sopenharmony_ci    div = '--------------------'
887db96d56Sopenharmony_ci    yield header
897db96d56Sopenharmony_ci    yield div
907db96d56Sopenharmony_ci    total = 0
917db96d56Sopenharmony_ci    for item in items:
927db96d56Sopenharmony_ci        rowdata = item.render_rowdata(columns)
937db96d56Sopenharmony_ci        row = [rowdata[c] for c in columns]
947db96d56Sopenharmony_ci        if relroot and 'file' in columns:
957db96d56Sopenharmony_ci            index = columns.index('file')
967db96d56Sopenharmony_ci            row[index] = os.path.relpath(row[index], relroot)
977db96d56Sopenharmony_ci        yield '\t'.join(row)
987db96d56Sopenharmony_ci        total += 1
997db96d56Sopenharmony_ci    yield div
1007db96d56Sopenharmony_ci    yield f'total: {total}'
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_cidef build_section(name, groupitems, *, relroot=None):
1047db96d56Sopenharmony_ci    info = TABLE_SECTIONS[name]
1057db96d56Sopenharmony_ci    while type(info) is not tuple:
1067db96d56Sopenharmony_ci        if name in KINDS:
1077db96d56Sopenharmony_ci            name = info
1087db96d56Sopenharmony_ci        info = TABLE_SECTIONS[info]
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci    columns, match_kind, sortkey = info
1117db96d56Sopenharmony_ci    items = (v for v in groupitems if match_kind(v.kind))
1127db96d56Sopenharmony_ci    items = sorted(items, key=sortkey)
1137db96d56Sopenharmony_ci    def render():
1147db96d56Sopenharmony_ci        yield ''
1157db96d56Sopenharmony_ci        yield f'{name}:'
1167db96d56Sopenharmony_ci        yield ''
1177db96d56Sopenharmony_ci        for line in _render_table(items, columns, relroot):
1187db96d56Sopenharmony_ci            yield line
1197db96d56Sopenharmony_ci    return items, render
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci#######################################
1237db96d56Sopenharmony_ci# the checks
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ciCHECKS = {
1267db96d56Sopenharmony_ci    #'globals': _check_globals,
1277db96d56Sopenharmony_ci}
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_cidef add_checks_cli(parser, checks=None, *, add_flags=None):
1317db96d56Sopenharmony_ci    default = False
1327db96d56Sopenharmony_ci    if not checks:
1337db96d56Sopenharmony_ci        checks = list(CHECKS)
1347db96d56Sopenharmony_ci        default = True
1357db96d56Sopenharmony_ci    elif isinstance(checks, str):
1367db96d56Sopenharmony_ci        checks = [checks]
1377db96d56Sopenharmony_ci    if (add_flags is None and len(checks) > 1) or default:
1387db96d56Sopenharmony_ci        add_flags = True
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci    process_checks = add_sepval_cli(parser, '--check', 'checks', checks)
1417db96d56Sopenharmony_ci    if add_flags:
1427db96d56Sopenharmony_ci        for check in checks:
1437db96d56Sopenharmony_ci            parser.add_argument(f'--{check}', dest='checks',
1447db96d56Sopenharmony_ci                                action='append_const', const=check)
1457db96d56Sopenharmony_ci    return [
1467db96d56Sopenharmony_ci        process_checks,
1477db96d56Sopenharmony_ci    ]
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_cidef _get_check_handlers(fmt, printer, verbosity=VERBOSITY):
1517db96d56Sopenharmony_ci    div = None
1527db96d56Sopenharmony_ci    def handle_after():
1537db96d56Sopenharmony_ci        pass
1547db96d56Sopenharmony_ci    if not fmt:
1557db96d56Sopenharmony_ci        div = ''
1567db96d56Sopenharmony_ci        def handle_failure(failure, data):
1577db96d56Sopenharmony_ci            data = repr(data)
1587db96d56Sopenharmony_ci            if verbosity >= 3:
1597db96d56Sopenharmony_ci                logger.info(f'failure: {failure}')
1607db96d56Sopenharmony_ci                logger.info(f'data:    {data}')
1617db96d56Sopenharmony_ci            else:
1627db96d56Sopenharmony_ci                logger.warn(f'failure: {failure} (data: {data})')
1637db96d56Sopenharmony_ci    elif fmt == 'raw':
1647db96d56Sopenharmony_ci        def handle_failure(failure, data):
1657db96d56Sopenharmony_ci            print(f'{failure!r} {data!r}')
1667db96d56Sopenharmony_ci    elif fmt == 'brief':
1677db96d56Sopenharmony_ci        def handle_failure(failure, data):
1687db96d56Sopenharmony_ci            parent = data.parent or ''
1697db96d56Sopenharmony_ci            funcname = parent if isinstance(parent, str) else parent.name
1707db96d56Sopenharmony_ci            name = f'({funcname}).{data.name}' if funcname else data.name
1717db96d56Sopenharmony_ci            failure = failure.split('\t')[0]
1727db96d56Sopenharmony_ci            print(f'{data.filename}:{name} - {failure}')
1737db96d56Sopenharmony_ci    elif fmt == 'summary':
1747db96d56Sopenharmony_ci        def handle_failure(failure, data):
1757db96d56Sopenharmony_ci            print(_fmt_one_summary(data, failure))
1767db96d56Sopenharmony_ci    elif fmt == 'full':
1777db96d56Sopenharmony_ci        div = ''
1787db96d56Sopenharmony_ci        def handle_failure(failure, data):
1797db96d56Sopenharmony_ci            name = data.shortkey if data.kind is KIND.VARIABLE else data.name
1807db96d56Sopenharmony_ci            parent = data.parent or ''
1817db96d56Sopenharmony_ci            funcname = parent if isinstance(parent, str) else parent.name
1827db96d56Sopenharmony_ci            known = 'yes' if data.is_known else '*** NO ***'
1837db96d56Sopenharmony_ci            print(f'{data.kind.value} {name!r} failed ({failure})')
1847db96d56Sopenharmony_ci            print(f'  file:         {data.filename}')
1857db96d56Sopenharmony_ci            print(f'  func:         {funcname or "-"}')
1867db96d56Sopenharmony_ci            print(f'  name:         {data.name}')
1877db96d56Sopenharmony_ci            print(f'  data:         ...')
1887db96d56Sopenharmony_ci            print(f'  type unknown: {known}')
1897db96d56Sopenharmony_ci    else:
1907db96d56Sopenharmony_ci        if fmt in FORMATS:
1917db96d56Sopenharmony_ci            raise NotImplementedError(fmt)
1927db96d56Sopenharmony_ci        raise ValueError(f'unsupported fmt {fmt!r}')
1937db96d56Sopenharmony_ci    return handle_failure, handle_after, div
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci#######################################
1977db96d56Sopenharmony_ci# the formats
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_cidef fmt_raw(analysis):
2007db96d56Sopenharmony_ci    for item in analysis:
2017db96d56Sopenharmony_ci        yield from item.render('raw')
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_cidef fmt_brief(analysis):
2057db96d56Sopenharmony_ci    # XXX Support sorting.
2067db96d56Sopenharmony_ci    items = sorted(analysis)
2077db96d56Sopenharmony_ci    for kind in KINDS:
2087db96d56Sopenharmony_ci        if kind is KIND.STATEMENT:
2097db96d56Sopenharmony_ci            continue
2107db96d56Sopenharmony_ci        for item in items:
2117db96d56Sopenharmony_ci            if item.kind is not kind:
2127db96d56Sopenharmony_ci                continue
2137db96d56Sopenharmony_ci            yield from item.render('brief')
2147db96d56Sopenharmony_ci    yield f'  total: {len(items)}'
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_cidef fmt_summary(analysis):
2187db96d56Sopenharmony_ci    # XXX Support sorting and grouping.
2197db96d56Sopenharmony_ci    items = list(analysis)
2207db96d56Sopenharmony_ci    total = len(items)
2217db96d56Sopenharmony_ci
2227db96d56Sopenharmony_ci    def section(name):
2237db96d56Sopenharmony_ci        _, render = build_section(name, items)
2247db96d56Sopenharmony_ci        yield from render()
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci    yield from section('types')
2277db96d56Sopenharmony_ci    yield from section('functions')
2287db96d56Sopenharmony_ci    yield from section('variables')
2297db96d56Sopenharmony_ci    yield from section('statements')
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci    yield ''
2327db96d56Sopenharmony_ci#    yield f'grand total: {len(supported) + len(unsupported)}'
2337db96d56Sopenharmony_ci    yield f'grand total: {total}'
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci
2367db96d56Sopenharmony_cidef _fmt_one_summary(item, extra=None):
2377db96d56Sopenharmony_ci    parent = item.parent or ''
2387db96d56Sopenharmony_ci    funcname = parent if isinstance(parent, str) else parent.name
2397db96d56Sopenharmony_ci    if extra:
2407db96d56Sopenharmony_ci        return f'{item.filename:35}\t{funcname or "-":35}\t{item.name:40}\t{extra}'
2417db96d56Sopenharmony_ci    else:
2427db96d56Sopenharmony_ci        return f'{item.filename:35}\t{funcname or "-":35}\t{item.name}'
2437db96d56Sopenharmony_ci
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_cidef fmt_full(analysis):
2467db96d56Sopenharmony_ci    # XXX Support sorting.
2477db96d56Sopenharmony_ci    items = sorted(analysis, key=lambda v: v.key)
2487db96d56Sopenharmony_ci    yield ''
2497db96d56Sopenharmony_ci    for item in items:
2507db96d56Sopenharmony_ci        yield from item.render('full')
2517db96d56Sopenharmony_ci        yield ''
2527db96d56Sopenharmony_ci    yield f'total: {len(items)}'
2537db96d56Sopenharmony_ci
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_ciFORMATS = {
2567db96d56Sopenharmony_ci    'raw': fmt_raw,
2577db96d56Sopenharmony_ci    'brief': fmt_brief,
2587db96d56Sopenharmony_ci    'summary': fmt_summary,
2597db96d56Sopenharmony_ci    'full': fmt_full,
2607db96d56Sopenharmony_ci}
2617db96d56Sopenharmony_ci
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_cidef add_output_cli(parser, *, default='summary'):
2647db96d56Sopenharmony_ci    parser.add_argument('--format', dest='fmt', default=default, choices=tuple(FORMATS))
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci    def process_args(args, *, argv=None):
2677db96d56Sopenharmony_ci        pass
2687db96d56Sopenharmony_ci    return process_args
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_ci
2717db96d56Sopenharmony_ci#######################################
2727db96d56Sopenharmony_ci# the commands
2737db96d56Sopenharmony_ci
2747db96d56Sopenharmony_cidef _cli_check(parser, checks=None, **kwargs):
2757db96d56Sopenharmony_ci    if isinstance(checks, str):
2767db96d56Sopenharmony_ci        checks = [checks]
2777db96d56Sopenharmony_ci    if checks is False:
2787db96d56Sopenharmony_ci        process_checks = None
2797db96d56Sopenharmony_ci    elif checks is None:
2807db96d56Sopenharmony_ci        process_checks = add_checks_cli(parser)
2817db96d56Sopenharmony_ci    elif len(checks) == 1 and type(checks) is not dict and re.match(r'^<.*>$', checks[0]):
2827db96d56Sopenharmony_ci        check = checks[0][1:-1]
2837db96d56Sopenharmony_ci        def process_checks(args, *, argv=None):
2847db96d56Sopenharmony_ci            args.checks = [check]
2857db96d56Sopenharmony_ci    else:
2867db96d56Sopenharmony_ci        process_checks = add_checks_cli(parser, checks=checks)
2877db96d56Sopenharmony_ci    process_progress = add_progress_cli(parser)
2887db96d56Sopenharmony_ci    process_output = add_output_cli(parser, default=None)
2897db96d56Sopenharmony_ci    process_files = add_files_cli(parser, **kwargs)
2907db96d56Sopenharmony_ci    return [
2917db96d56Sopenharmony_ci        process_checks,
2927db96d56Sopenharmony_ci        process_progress,
2937db96d56Sopenharmony_ci        process_output,
2947db96d56Sopenharmony_ci        process_files,
2957db96d56Sopenharmony_ci    ]
2967db96d56Sopenharmony_ci
2977db96d56Sopenharmony_ci
2987db96d56Sopenharmony_cidef cmd_check(filenames, *,
2997db96d56Sopenharmony_ci              checks=None,
3007db96d56Sopenharmony_ci              ignored=None,
3017db96d56Sopenharmony_ci              fmt=None,
3027db96d56Sopenharmony_ci              failfast=False,
3037db96d56Sopenharmony_ci              iter_filenames=None,
3047db96d56Sopenharmony_ci              relroot=fsutil.USE_CWD,
3057db96d56Sopenharmony_ci              track_progress=None,
3067db96d56Sopenharmony_ci              verbosity=VERBOSITY,
3077db96d56Sopenharmony_ci              _analyze=_analyze,
3087db96d56Sopenharmony_ci              _CHECKS=CHECKS,
3097db96d56Sopenharmony_ci              **kwargs
3107db96d56Sopenharmony_ci              ):
3117db96d56Sopenharmony_ci    if not checks:
3127db96d56Sopenharmony_ci        checks = _CHECKS
3137db96d56Sopenharmony_ci    elif isinstance(checks, str):
3147db96d56Sopenharmony_ci        checks = [checks]
3157db96d56Sopenharmony_ci    checks = [_CHECKS[c] if isinstance(c, str) else c
3167db96d56Sopenharmony_ci              for c in checks]
3177db96d56Sopenharmony_ci    printer = Printer(verbosity)
3187db96d56Sopenharmony_ci    (handle_failure, handle_after, div
3197db96d56Sopenharmony_ci     ) = _get_check_handlers(fmt, printer, verbosity)
3207db96d56Sopenharmony_ci
3217db96d56Sopenharmony_ci    filenames, relroot = fsutil.fix_filenames(filenames, relroot=relroot)
3227db96d56Sopenharmony_ci    filenames = filter_filenames(filenames, iter_filenames, relroot)
3237db96d56Sopenharmony_ci    if track_progress:
3247db96d56Sopenharmony_ci        filenames = track_progress(filenames)
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci    logger.info('analyzing files...')
3277db96d56Sopenharmony_ci    analyzed = _analyze(filenames, **kwargs)
3287db96d56Sopenharmony_ci    analyzed.fix_filenames(relroot, normalize=False)
3297db96d56Sopenharmony_ci    decls = filter_forward(analyzed, markpublic=True)
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci    logger.info('checking analysis results...')
3327db96d56Sopenharmony_ci    failed = []
3337db96d56Sopenharmony_ci    for data, failure in _check_all(decls, checks, failfast=failfast):
3347db96d56Sopenharmony_ci        if data is None:
3357db96d56Sopenharmony_ci            printer.info('stopping after one failure')
3367db96d56Sopenharmony_ci            break
3377db96d56Sopenharmony_ci        if div is not None and len(failed) > 0:
3387db96d56Sopenharmony_ci            printer.info(div)
3397db96d56Sopenharmony_ci        failed.append(data)
3407db96d56Sopenharmony_ci        handle_failure(failure, data)
3417db96d56Sopenharmony_ci    handle_after()
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_ci    printer.info('-------------------------')
3447db96d56Sopenharmony_ci    logger.info(f'total failures: {len(failed)}')
3457db96d56Sopenharmony_ci    logger.info('done checking')
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ci    if fmt == 'summary':
3487db96d56Sopenharmony_ci        print('Categorized by storage:')
3497db96d56Sopenharmony_ci        print()
3507db96d56Sopenharmony_ci        from .match import group_by_storage
3517db96d56Sopenharmony_ci        grouped = group_by_storage(failed, ignore_non_match=False)
3527db96d56Sopenharmony_ci        for group, decls in grouped.items():
3537db96d56Sopenharmony_ci            print()
3547db96d56Sopenharmony_ci            print(group)
3557db96d56Sopenharmony_ci            for decl in decls:
3567db96d56Sopenharmony_ci                print(' ', _fmt_one_summary(decl))
3577db96d56Sopenharmony_ci            print(f'subtotal: {len(decls)}')
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci    if len(failed) > 0:
3607db96d56Sopenharmony_ci        sys.exit(len(failed))
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci
3637db96d56Sopenharmony_cidef _cli_analyze(parser, **kwargs):
3647db96d56Sopenharmony_ci    process_progress = add_progress_cli(parser)
3657db96d56Sopenharmony_ci    process_output = add_output_cli(parser)
3667db96d56Sopenharmony_ci    process_files = add_files_cli(parser, **kwargs)
3677db96d56Sopenharmony_ci    return [
3687db96d56Sopenharmony_ci        process_progress,
3697db96d56Sopenharmony_ci        process_output,
3707db96d56Sopenharmony_ci        process_files,
3717db96d56Sopenharmony_ci    ]
3727db96d56Sopenharmony_ci
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci# XXX Support filtering by kind.
3757db96d56Sopenharmony_cidef cmd_analyze(filenames, *,
3767db96d56Sopenharmony_ci                fmt=None,
3777db96d56Sopenharmony_ci                iter_filenames=None,
3787db96d56Sopenharmony_ci                relroot=fsutil.USE_CWD,
3797db96d56Sopenharmony_ci                track_progress=None,
3807db96d56Sopenharmony_ci                verbosity=None,
3817db96d56Sopenharmony_ci                _analyze=_analyze,
3827db96d56Sopenharmony_ci                formats=FORMATS,
3837db96d56Sopenharmony_ci                **kwargs
3847db96d56Sopenharmony_ci                ):
3857db96d56Sopenharmony_ci    verbosity = verbosity if verbosity is not None else 3
3867db96d56Sopenharmony_ci
3877db96d56Sopenharmony_ci    try:
3887db96d56Sopenharmony_ci        do_fmt = formats[fmt]
3897db96d56Sopenharmony_ci    except KeyError:
3907db96d56Sopenharmony_ci        raise ValueError(f'unsupported fmt {fmt!r}')
3917db96d56Sopenharmony_ci
3927db96d56Sopenharmony_ci    filenames, relroot = fsutil.fix_filenames(filenames, relroot=relroot)
3937db96d56Sopenharmony_ci    filenames = filter_filenames(filenames, iter_filenames, relroot)
3947db96d56Sopenharmony_ci    if track_progress:
3957db96d56Sopenharmony_ci        filenames = track_progress(filenames)
3967db96d56Sopenharmony_ci
3977db96d56Sopenharmony_ci    logger.info('analyzing files...')
3987db96d56Sopenharmony_ci    analyzed = _analyze(filenames, **kwargs)
3997db96d56Sopenharmony_ci    analyzed.fix_filenames(relroot, normalize=False)
4007db96d56Sopenharmony_ci    decls = filter_forward(analyzed, markpublic=True)
4017db96d56Sopenharmony_ci
4027db96d56Sopenharmony_ci    for line in do_fmt(decls):
4037db96d56Sopenharmony_ci        print(line)
4047db96d56Sopenharmony_ci
4057db96d56Sopenharmony_ci
4067db96d56Sopenharmony_cidef _cli_data(parser, filenames=None, known=None):
4077db96d56Sopenharmony_ci    ArgumentParser = type(parser)
4087db96d56Sopenharmony_ci    common = ArgumentParser(add_help=False)
4097db96d56Sopenharmony_ci    # These flags will get processed by the top-level parse_args().
4107db96d56Sopenharmony_ci    add_verbosity_cli(common)
4117db96d56Sopenharmony_ci    add_traceback_cli(common)
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_ci    subs = parser.add_subparsers(dest='datacmd')
4147db96d56Sopenharmony_ci
4157db96d56Sopenharmony_ci    sub = subs.add_parser('show', parents=[common])
4167db96d56Sopenharmony_ci    if known is None:
4177db96d56Sopenharmony_ci        sub.add_argument('--known', required=True)
4187db96d56Sopenharmony_ci    if filenames is None:
4197db96d56Sopenharmony_ci        sub.add_argument('filenames', metavar='FILE', nargs='+')
4207db96d56Sopenharmony_ci
4217db96d56Sopenharmony_ci    sub = subs.add_parser('dump', parents=[common])
4227db96d56Sopenharmony_ci    if known is None:
4237db96d56Sopenharmony_ci        sub.add_argument('--known')
4247db96d56Sopenharmony_ci    sub.add_argument('--show', action='store_true')
4257db96d56Sopenharmony_ci    process_progress = add_progress_cli(sub)
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci    sub = subs.add_parser('check', parents=[common])
4287db96d56Sopenharmony_ci    if known is None:
4297db96d56Sopenharmony_ci        sub.add_argument('--known', required=True)
4307db96d56Sopenharmony_ci
4317db96d56Sopenharmony_ci    def process_args(args, *, argv):
4327db96d56Sopenharmony_ci        if args.datacmd == 'dump':
4337db96d56Sopenharmony_ci            process_progress(args, argv)
4347db96d56Sopenharmony_ci    return process_args
4357db96d56Sopenharmony_ci
4367db96d56Sopenharmony_ci
4377db96d56Sopenharmony_cidef cmd_data(datacmd, filenames, known=None, *,
4387db96d56Sopenharmony_ci             _analyze=_analyze,
4397db96d56Sopenharmony_ci             formats=FORMATS,
4407db96d56Sopenharmony_ci             extracolumns=None,
4417db96d56Sopenharmony_ci             relroot=fsutil.USE_CWD,
4427db96d56Sopenharmony_ci             track_progress=None,
4437db96d56Sopenharmony_ci             **kwargs
4447db96d56Sopenharmony_ci             ):
4457db96d56Sopenharmony_ci    kwargs.pop('verbosity', None)
4467db96d56Sopenharmony_ci    usestdout = kwargs.pop('show', None)
4477db96d56Sopenharmony_ci    if datacmd == 'show':
4487db96d56Sopenharmony_ci        do_fmt = formats['summary']
4497db96d56Sopenharmony_ci        if isinstance(known, str):
4507db96d56Sopenharmony_ci            known, _ = _datafiles.get_known(known, extracolumns, relroot)
4517db96d56Sopenharmony_ci        for line in do_fmt(known):
4527db96d56Sopenharmony_ci            print(line)
4537db96d56Sopenharmony_ci    elif datacmd == 'dump':
4547db96d56Sopenharmony_ci        filenames, relroot = fsutil.fix_filenames(filenames, relroot=relroot)
4557db96d56Sopenharmony_ci        if track_progress:
4567db96d56Sopenharmony_ci            filenames = track_progress(filenames)
4577db96d56Sopenharmony_ci        analyzed = _analyze(filenames, **kwargs)
4587db96d56Sopenharmony_ci        analyzed.fix_filenames(relroot, normalize=False)
4597db96d56Sopenharmony_ci        if known is None or usestdout:
4607db96d56Sopenharmony_ci            outfile = io.StringIO()
4617db96d56Sopenharmony_ci            _datafiles.write_known(analyzed, outfile, extracolumns,
4627db96d56Sopenharmony_ci                                   relroot=relroot)
4637db96d56Sopenharmony_ci            print(outfile.getvalue())
4647db96d56Sopenharmony_ci        else:
4657db96d56Sopenharmony_ci            _datafiles.write_known(analyzed, known, extracolumns,
4667db96d56Sopenharmony_ci                                   relroot=relroot)
4677db96d56Sopenharmony_ci    elif datacmd == 'check':
4687db96d56Sopenharmony_ci        raise NotImplementedError(datacmd)
4697db96d56Sopenharmony_ci    else:
4707db96d56Sopenharmony_ci        raise ValueError(f'unsupported data command {datacmd!r}')
4717db96d56Sopenharmony_ci
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ciCOMMANDS = {
4747db96d56Sopenharmony_ci    'check': (
4757db96d56Sopenharmony_ci        'analyze and fail if the given C source/header files have any problems',
4767db96d56Sopenharmony_ci        [_cli_check],
4777db96d56Sopenharmony_ci        cmd_check,
4787db96d56Sopenharmony_ci    ),
4797db96d56Sopenharmony_ci    'analyze': (
4807db96d56Sopenharmony_ci        'report on the state of the given C source/header files',
4817db96d56Sopenharmony_ci        [_cli_analyze],
4827db96d56Sopenharmony_ci        cmd_analyze,
4837db96d56Sopenharmony_ci    ),
4847db96d56Sopenharmony_ci    'data': (
4857db96d56Sopenharmony_ci        'check/manage local data (e.g. known types, ignored vars, caches)',
4867db96d56Sopenharmony_ci        [_cli_data],
4877db96d56Sopenharmony_ci        cmd_data,
4887db96d56Sopenharmony_ci    ),
4897db96d56Sopenharmony_ci}
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_ci
4927db96d56Sopenharmony_ci#######################################
4937db96d56Sopenharmony_ci# the script
4947db96d56Sopenharmony_ci
4957db96d56Sopenharmony_cidef parse_args(argv=sys.argv[1:], prog=sys.argv[0], *, subset=None):
4967db96d56Sopenharmony_ci    import argparse
4977db96d56Sopenharmony_ci    parser = argparse.ArgumentParser(
4987db96d56Sopenharmony_ci        prog=prog or get_prog(),
4997db96d56Sopenharmony_ci    )
5007db96d56Sopenharmony_ci
5017db96d56Sopenharmony_ci    processors = add_commands_cli(
5027db96d56Sopenharmony_ci        parser,
5037db96d56Sopenharmony_ci        commands={k: v[1] for k, v in COMMANDS.items()},
5047db96d56Sopenharmony_ci        commonspecs=[
5057db96d56Sopenharmony_ci            add_verbosity_cli,
5067db96d56Sopenharmony_ci            add_traceback_cli,
5077db96d56Sopenharmony_ci        ],
5087db96d56Sopenharmony_ci        subset=subset,
5097db96d56Sopenharmony_ci    )
5107db96d56Sopenharmony_ci
5117db96d56Sopenharmony_ci    args = parser.parse_args(argv)
5127db96d56Sopenharmony_ci    ns = vars(args)
5137db96d56Sopenharmony_ci
5147db96d56Sopenharmony_ci    cmd = ns.pop('cmd')
5157db96d56Sopenharmony_ci
5167db96d56Sopenharmony_ci    verbosity, traceback_cm = process_args_by_key(
5177db96d56Sopenharmony_ci        args,
5187db96d56Sopenharmony_ci        argv,
5197db96d56Sopenharmony_ci        processors[cmd],
5207db96d56Sopenharmony_ci        ['verbosity', 'traceback_cm'],
5217db96d56Sopenharmony_ci    )
5227db96d56Sopenharmony_ci    # "verbosity" is sent to the commands, so we put it back.
5237db96d56Sopenharmony_ci    args.verbosity = verbosity
5247db96d56Sopenharmony_ci
5257db96d56Sopenharmony_ci    return cmd, ns, verbosity, traceback_cm
5267db96d56Sopenharmony_ci
5277db96d56Sopenharmony_ci
5287db96d56Sopenharmony_cidef main(cmd, cmd_kwargs):
5297db96d56Sopenharmony_ci    try:
5307db96d56Sopenharmony_ci        run_cmd = COMMANDS[cmd][0]
5317db96d56Sopenharmony_ci    except KeyError:
5327db96d56Sopenharmony_ci        raise ValueError(f'unsupported cmd {cmd!r}')
5337db96d56Sopenharmony_ci    run_cmd(**cmd_kwargs)
5347db96d56Sopenharmony_ci
5357db96d56Sopenharmony_ci
5367db96d56Sopenharmony_ciif __name__ == '__main__':
5377db96d56Sopenharmony_ci    cmd, cmd_kwargs, verbosity, traceback_cm = parse_args()
5387db96d56Sopenharmony_ci    configure_logger(verbosity)
5397db96d56Sopenharmony_ci    with traceback_cm:
5407db96d56Sopenharmony_ci        main(cmd, cmd_kwargs)
541