]>
Commit | Line | Data |
---|---|---|
94dfc0f3 EH |
1 | #!/usr/bin/env python3 |
2 | # QEMU library | |
3 | # | |
4 | # Copyright (C) 2020 Red Hat Inc. | |
5 | # | |
6 | # Authors: | |
7 | # Eduardo Habkost <ehabkost@redhat.com> | |
8 | # | |
9 | # This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | # the COPYING file in the top-level directory. | |
11 | # | |
12 | import sys | |
13 | import argparse | |
14 | import os | |
15 | import os.path | |
16 | import re | |
17 | from typing import * | |
18 | ||
19 | from codeconverter.patching import FileInfo, match_class_dict, FileList | |
20 | import codeconverter.qom_macros | |
21 | from codeconverter.qom_type_info import TI_FIELDS, type_infos, TypeInfoVar | |
22 | ||
23 | import logging | |
24 | logger = logging.getLogger(__name__) | |
25 | DBG = logger.debug | |
26 | INFO = logger.info | |
27 | WARN = logger.warning | |
28 | ||
29 | def process_all_files(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None: | |
30 | DBG("filenames: %r", args.filenames) | |
31 | ||
32 | files = FileList() | |
33 | files.extend(FileInfo(files, fn, args.force) for fn in args.filenames) | |
34 | for f in files: | |
35 | DBG('opening %s', f.filename) | |
36 | f.load() | |
37 | ||
38 | if args.table: | |
39 | fields = ['filename', 'variable_name'] + TI_FIELDS | |
40 | print('\t'.join(fields)) | |
41 | for f in files: | |
42 | for t in f.matches_of_type(TypeInfoVar): | |
43 | assert isinstance(t, TypeInfoVar) | |
44 | values = [f.filename, t.name] + \ | |
4a15e5be | 45 | [t.get_raw_initializer_value(f) |
94dfc0f3 EH |
46 | for f in TI_FIELDS] |
47 | DBG('values: %r', values) | |
48 | assert all('\t' not in v for v in values) | |
49 | values = [v.replace('\n', ' ').replace('"', '') for v in values] | |
50 | print('\t'.join(values)) | |
51 | return | |
52 | ||
53 | match_classes = match_class_dict() | |
54 | if not args.patterns: | |
55 | parser.error("--pattern is required") | |
56 | ||
57 | classes = [p for arg in args.patterns | |
4a15e5be EH |
58 | for p in re.split(r'[\s,]', arg) |
59 | if p.strip()] | |
94dfc0f3 | 60 | for c in classes: |
4a15e5be EH |
61 | if c not in match_classes \ |
62 | or not match_classes[c].regexp: | |
94dfc0f3 EH |
63 | print("Invalid pattern name: %s" % (c), file=sys.stderr) |
64 | print("Valid patterns:", file=sys.stderr) | |
65 | print(PATTERN_HELP, file=sys.stderr) | |
66 | sys.exit(1) | |
67 | ||
68 | DBG("classes: %r", classes) | |
4a15e5be | 69 | files.patch_content(max_passes=args.passes, class_names=classes) |
94dfc0f3 EH |
70 | |
71 | for f in files: | |
72 | #alltypes.extend(f.type_infos) | |
73 | #full_types.extend(f.full_types()) | |
74 | ||
75 | if not args.dry_run: | |
76 | if args.inplace: | |
77 | f.patch_inplace() | |
78 | if args.diff: | |
79 | f.show_diff() | |
80 | if not args.diff and not args.inplace: | |
81 | f.write_to_file(sys.stdout) | |
82 | sys.stdout.flush() | |
83 | ||
84 | ||
85 | PATTERN_HELP = ('\n'.join(" %s: %s" % (n, str(c.__doc__).strip()) | |
86 | for (n,c) in sorted(match_class_dict().items()) | |
87 | if c.has_replacement_rule())) | |
88 | ||
89 | def main() -> None: | |
90 | p = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) | |
91 | p.add_argument('filenames', nargs='+') | |
92 | p.add_argument('--passes', type=int, default=1, | |
93 | help="Number of passes (0 means unlimited)") | |
94 | p.add_argument('--pattern', required=True, action='append', | |
95 | default=[], dest='patterns', | |
96 | help="Pattern to scan for") | |
97 | p.add_argument('--inplace', '-i', action='store_true', | |
98 | help="Patch file in place") | |
99 | p.add_argument('--dry-run', action='store_true', | |
100 | help="Don't patch files or print patching results") | |
101 | p.add_argument('--force', '-f', action='store_true', | |
102 | help="Perform changes even if not completely safe") | |
103 | p.add_argument('--diff', action='store_true', | |
104 | help="Print diff output on stdout") | |
105 | p.add_argument('--debug', '-d', action='store_true', | |
106 | help="Enable debugging") | |
107 | p.add_argument('--verbose', '-v', action='store_true', | |
108 | help="Verbose logging on stderr") | |
109 | p.add_argument('--table', action='store_true', | |
110 | help="Print CSV table of type information") | |
111 | p.add_argument_group("Valid pattern names", | |
112 | PATTERN_HELP) | |
113 | args = p.parse_args() | |
114 | ||
115 | loglevel = (logging.DEBUG if args.debug | |
116 | else logging.INFO if args.verbose | |
117 | else logging.WARN) | |
118 | logging.basicConfig(format='%(levelname)s: %(message)s', level=loglevel) | |
119 | DBG("args: %r", args) | |
120 | process_all_files(p, args) | |
121 | ||
122 | if __name__ == '__main__': | |
123 | main() |