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()