xref: /openbmc/qemu/scripts/codeconverter/converter.py (revision 4dad0a9aa818698e0735c8352bf7925a1660df6f)
194dfc0f3SEduardo Habkost#!/usr/bin/env python3
294dfc0f3SEduardo Habkost# QEMU library
394dfc0f3SEduardo Habkost#
494dfc0f3SEduardo Habkost# Copyright (C) 2020 Red Hat Inc.
594dfc0f3SEduardo Habkost#
694dfc0f3SEduardo Habkost# Authors:
794dfc0f3SEduardo Habkost#  Eduardo Habkost <ehabkost@redhat.com>
894dfc0f3SEduardo Habkost#
994dfc0f3SEduardo Habkost# This work is licensed under the terms of the GNU GPL, version 2.  See
1094dfc0f3SEduardo Habkost# the COPYING file in the top-level directory.
1194dfc0f3SEduardo Habkost#
1294dfc0f3SEduardo Habkostimport sys
1394dfc0f3SEduardo Habkostimport argparse
1494dfc0f3SEduardo Habkostimport os
1594dfc0f3SEduardo Habkostimport os.path
1694dfc0f3SEduardo Habkostimport re
1794dfc0f3SEduardo Habkostfrom typing import *
1894dfc0f3SEduardo Habkost
1994dfc0f3SEduardo Habkostfrom codeconverter.patching import FileInfo, match_class_dict, FileList
2094dfc0f3SEduardo Habkostimport codeconverter.qom_macros
2194dfc0f3SEduardo Habkostfrom codeconverter.qom_type_info import TI_FIELDS, type_infos, TypeInfoVar
2294dfc0f3SEduardo Habkost
2394dfc0f3SEduardo Habkostimport logging
2494dfc0f3SEduardo Habkostlogger = logging.getLogger(__name__)
2594dfc0f3SEduardo HabkostDBG = logger.debug
2694dfc0f3SEduardo HabkostINFO = logger.info
2794dfc0f3SEduardo HabkostWARN = logger.warning
2894dfc0f3SEduardo Habkost
2994dfc0f3SEduardo Habkostdef process_all_files(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None:
3094dfc0f3SEduardo Habkost    DBG("filenames: %r", args.filenames)
3194dfc0f3SEduardo Habkost
3294dfc0f3SEduardo Habkost    files = FileList()
3394dfc0f3SEduardo Habkost    files.extend(FileInfo(files, fn, args.force) for fn in args.filenames)
3494dfc0f3SEduardo Habkost    for f in files:
3594dfc0f3SEduardo Habkost        DBG('opening %s', f.filename)
3694dfc0f3SEduardo Habkost        f.load()
3794dfc0f3SEduardo Habkost
3894dfc0f3SEduardo Habkost    if args.table:
3994dfc0f3SEduardo Habkost        fields = ['filename', 'variable_name'] + TI_FIELDS
4094dfc0f3SEduardo Habkost        print('\t'.join(fields))
4194dfc0f3SEduardo Habkost        for f in files:
4294dfc0f3SEduardo Habkost            for t in f.matches_of_type(TypeInfoVar):
4394dfc0f3SEduardo Habkost                assert isinstance(t, TypeInfoVar)
4494dfc0f3SEduardo Habkost                values = [f.filename, t.name] + \
45*4a15e5beSEduardo Habkost                         [t.get_raw_initializer_value(f)
4694dfc0f3SEduardo Habkost                          for f in TI_FIELDS]
4794dfc0f3SEduardo Habkost                DBG('values: %r', values)
4894dfc0f3SEduardo Habkost                assert all('\t' not in v for v in values)
4994dfc0f3SEduardo Habkost                values = [v.replace('\n', ' ').replace('"', '') for v in values]
5094dfc0f3SEduardo Habkost                print('\t'.join(values))
5194dfc0f3SEduardo Habkost        return
5294dfc0f3SEduardo Habkost
5394dfc0f3SEduardo Habkost    match_classes = match_class_dict()
5494dfc0f3SEduardo Habkost    if not args.patterns:
5594dfc0f3SEduardo Habkost        parser.error("--pattern is required")
5694dfc0f3SEduardo Habkost
5794dfc0f3SEduardo Habkost    classes = [p for arg in args.patterns
58*4a15e5beSEduardo Habkost               for p in re.split(r'[\s,]', arg)
59*4a15e5beSEduardo Habkost               if p.strip()]
6094dfc0f3SEduardo Habkost    for c in classes:
61*4a15e5beSEduardo Habkost        if c not in match_classes \
62*4a15e5beSEduardo Habkost           or not match_classes[c].regexp:
6394dfc0f3SEduardo Habkost            print("Invalid pattern name: %s" % (c), file=sys.stderr)
6494dfc0f3SEduardo Habkost            print("Valid patterns:", file=sys.stderr)
6594dfc0f3SEduardo Habkost            print(PATTERN_HELP, file=sys.stderr)
6694dfc0f3SEduardo Habkost            sys.exit(1)
6794dfc0f3SEduardo Habkost
6894dfc0f3SEduardo Habkost    DBG("classes: %r", classes)
69*4a15e5beSEduardo Habkost    files.patch_content(max_passes=args.passes, class_names=classes)
7094dfc0f3SEduardo Habkost
7194dfc0f3SEduardo Habkost    for f in files:
7294dfc0f3SEduardo Habkost        #alltypes.extend(f.type_infos)
7394dfc0f3SEduardo Habkost        #full_types.extend(f.full_types())
7494dfc0f3SEduardo Habkost
7594dfc0f3SEduardo Habkost        if not args.dry_run:
7694dfc0f3SEduardo Habkost            if args.inplace:
7794dfc0f3SEduardo Habkost                f.patch_inplace()
7894dfc0f3SEduardo Habkost            if args.diff:
7994dfc0f3SEduardo Habkost                f.show_diff()
8094dfc0f3SEduardo Habkost            if not args.diff and not args.inplace:
8194dfc0f3SEduardo Habkost                f.write_to_file(sys.stdout)
8294dfc0f3SEduardo Habkost                sys.stdout.flush()
8394dfc0f3SEduardo Habkost
8494dfc0f3SEduardo Habkost
8594dfc0f3SEduardo HabkostPATTERN_HELP = ('\n'.join("  %s: %s" % (n, str(c.__doc__).strip())
8694dfc0f3SEduardo Habkost                for (n,c) in sorted(match_class_dict().items())
8794dfc0f3SEduardo Habkost                if c.has_replacement_rule()))
8894dfc0f3SEduardo Habkost
8994dfc0f3SEduardo Habkostdef main() -> None:
9094dfc0f3SEduardo Habkost    p = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
9194dfc0f3SEduardo Habkost    p.add_argument('filenames', nargs='+')
9294dfc0f3SEduardo Habkost    p.add_argument('--passes', type=int, default=1,
9394dfc0f3SEduardo Habkost                   help="Number of passes (0 means unlimited)")
9494dfc0f3SEduardo Habkost    p.add_argument('--pattern', required=True, action='append',
9594dfc0f3SEduardo Habkost                   default=[], dest='patterns',
9694dfc0f3SEduardo Habkost                   help="Pattern to scan for")
9794dfc0f3SEduardo Habkost    p.add_argument('--inplace', '-i', action='store_true',
9894dfc0f3SEduardo Habkost                   help="Patch file in place")
9994dfc0f3SEduardo Habkost    p.add_argument('--dry-run', action='store_true',
10094dfc0f3SEduardo Habkost                   help="Don't patch files or print patching results")
10194dfc0f3SEduardo Habkost    p.add_argument('--force', '-f', action='store_true',
10294dfc0f3SEduardo Habkost                   help="Perform changes even if not completely safe")
10394dfc0f3SEduardo Habkost    p.add_argument('--diff', action='store_true',
10494dfc0f3SEduardo Habkost                   help="Print diff output on stdout")
10594dfc0f3SEduardo Habkost    p.add_argument('--debug', '-d', action='store_true',
10694dfc0f3SEduardo Habkost                   help="Enable debugging")
10794dfc0f3SEduardo Habkost    p.add_argument('--verbose', '-v', action='store_true',
10894dfc0f3SEduardo Habkost                   help="Verbose logging on stderr")
10994dfc0f3SEduardo Habkost    p.add_argument('--table', action='store_true',
11094dfc0f3SEduardo Habkost                   help="Print CSV table of type information")
11194dfc0f3SEduardo Habkost    p.add_argument_group("Valid pattern names",
11294dfc0f3SEduardo Habkost                         PATTERN_HELP)
11394dfc0f3SEduardo Habkost    args = p.parse_args()
11494dfc0f3SEduardo Habkost
11594dfc0f3SEduardo Habkost    loglevel = (logging.DEBUG if args.debug
11694dfc0f3SEduardo Habkost             else logging.INFO if args.verbose
11794dfc0f3SEduardo Habkost             else logging.WARN)
11894dfc0f3SEduardo Habkost    logging.basicConfig(format='%(levelname)s: %(message)s', level=loglevel)
11994dfc0f3SEduardo Habkost    DBG("args: %r", args)
12094dfc0f3SEduardo Habkost    process_all_files(p, args)
12194dfc0f3SEduardo Habkost
12294dfc0f3SEduardo Habkostif __name__ == '__main__':
12394dfc0f3SEduardo Habkost    main()