converter.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. from codeconverter.patching import FileInfo, match_class_dict, FileList
  19. import codeconverter.qom_macros
  20. from codeconverter.qom_type_info import TI_FIELDS, type_infos, TypeInfoVar
  21. import logging
  22. logger = logging.getLogger(__name__)
  23. DBG = logger.debug
  24. INFO = logger.info
  25. WARN = logger.warning
  26. def process_all_files(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None:
  27. DBG("filenames: %r", args.filenames)
  28. files = FileList()
  29. files.extend(FileInfo(files, fn, args.force) for fn in args.filenames)
  30. for f in files:
  31. DBG('opening %s', f.filename)
  32. f.load()
  33. if args.table:
  34. fields = ['filename', 'variable_name'] + TI_FIELDS
  35. print('\t'.join(fields))
  36. for f in files:
  37. for t in f.matches_of_type(TypeInfoVar):
  38. assert isinstance(t, TypeInfoVar)
  39. values = [f.filename, t.name] + \
  40. [t.get_raw_initializer_value(f)
  41. for f in TI_FIELDS]
  42. DBG('values: %r', values)
  43. assert all('\t' not in v for v in values)
  44. values = [v.replace('\n', ' ').replace('"', '') for v in values]
  45. print('\t'.join(values))
  46. return
  47. match_classes = match_class_dict()
  48. if not args.patterns:
  49. parser.error("--pattern is required")
  50. classes = [p for arg in args.patterns
  51. for p in re.split(r'[\s,]', arg)
  52. if p.strip()]
  53. for c in classes:
  54. if c not in match_classes \
  55. or not match_classes[c].regexp:
  56. print("Invalid pattern name: %s" % (c), file=sys.stderr)
  57. print("Valid patterns:", file=sys.stderr)
  58. print(PATTERN_HELP, file=sys.stderr)
  59. sys.exit(1)
  60. DBG("classes: %r", classes)
  61. files.patch_content(max_passes=args.passes, class_names=classes)
  62. for f in files:
  63. #alltypes.extend(f.type_infos)
  64. #full_types.extend(f.full_types())
  65. if not args.dry_run:
  66. if args.inplace:
  67. f.patch_inplace()
  68. if args.diff:
  69. f.show_diff()
  70. if not args.diff and not args.inplace:
  71. f.write_to_file(sys.stdout)
  72. sys.stdout.flush()
  73. PATTERN_HELP = ('\n'.join(" %s: %s" % (n, str(c.__doc__).strip())
  74. for (n,c) in sorted(match_class_dict().items())
  75. if c.has_replacement_rule()))
  76. def main() -> None:
  77. p = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
  78. p.add_argument('filenames', nargs='+')
  79. p.add_argument('--passes', type=int, default=1,
  80. help="Number of passes (0 means unlimited)")
  81. p.add_argument('--pattern', required=True, action='append',
  82. default=[], dest='patterns',
  83. help="Pattern to scan for")
  84. p.add_argument('--inplace', '-i', action='store_true',
  85. help="Patch file in place")
  86. p.add_argument('--dry-run', action='store_true',
  87. help="Don't patch files or print patching results")
  88. p.add_argument('--force', '-f', action='store_true',
  89. help="Perform changes even if not completely safe")
  90. p.add_argument('--diff', action='store_true',
  91. help="Print diff output on stdout")
  92. p.add_argument('--debug', '-d', action='store_true',
  93. help="Enable debugging")
  94. p.add_argument('--verbose', '-v', action='store_true',
  95. help="Verbose logging on stderr")
  96. p.add_argument('--table', action='store_true',
  97. help="Print CSV table of type information")
  98. p.add_argument_group("Valid pattern names",
  99. PATTERN_HELP)
  100. args = p.parse_args()
  101. loglevel = (logging.DEBUG if args.debug
  102. else logging.INFO if args.verbose
  103. else logging.WARN)
  104. logging.basicConfig(format='%(levelname)s: %(message)s', level=loglevel)
  105. DBG("args: %r", args)
  106. process_all_files(p, args)
  107. if __name__ == '__main__':
  108. main()