rename.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #!/usr/bin/env python3
  2. # WHAT IS THIS?
  3. # This script renames symbols in the API, updating SDL_oldnames.h and
  4. # adding documentation for the change.
  5. import argparse
  6. import os
  7. import pathlib
  8. import pprint
  9. import re
  10. SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
  11. SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3"
  12. def main():
  13. # Check whether we can still modify the ABI
  14. version_header = pathlib.Path( SDL_INCLUDE_DIR / "SDL_version.h" ).read_text()
  15. if not re.search("SDL_MINOR_VERSION\s+[01]\s", version_header):
  16. raise Exception("ABI is frozen, symbols cannot be renamed")
  17. pattern = re.compile(r"\b%s\b" % args.oldname)
  18. # Find the symbol in the headers
  19. if pathlib.Path(args.header).is_file():
  20. header = pathlib.Path(args.header)
  21. else:
  22. header = pathlib.Path(SDL_INCLUDE_DIR / args.header)
  23. if not header.exists():
  24. raise Exception("Couldn't find header %s" % header)
  25. if not pattern.search(header.read_text()):
  26. raise Exception("Couldn't find %s in %s" % (args.oldname, header))
  27. # Replace the symbol in source code and documentation
  28. for dir in ['src', 'test', 'include']:
  29. replace_symbol_recursive(SDL_ROOT / dir, pattern, args.newname)
  30. if not args.code_only:
  31. replace_symbol_recursive(SDL_ROOT / 'docs', pattern, args.newname)
  32. add_symbol_to_oldnames(header.name, args.oldname, args.newname)
  33. add_symbol_to_migration(header.name, args.type, args.oldname, args.newname)
  34. add_symbol_to_whatsnew(args.type, args.oldname, args.newname)
  35. def replace_symbol_recursive(path, pattern, replacement):
  36. for entry in path.glob("*"):
  37. if entry.is_dir():
  38. replace_symbol_recursive(entry, pattern, replacement)
  39. elif not entry.name.endswith((".bmp", ".cur", ".dat", ".icns", ".png", ".strings", ".swp", ".wav")) and \
  40. entry.name != "utf8.txt":
  41. print("Processing %s" % entry)
  42. with entry.open('r', encoding='UTF-8', newline='') as rfp:
  43. contents = pattern.sub(replacement, rfp.read())
  44. with entry.open('w', encoding='UTF-8', newline='') as wfp:
  45. wfp.write(contents)
  46. def add_line(lines, i, section):
  47. lines.insert(i, section)
  48. i += 1
  49. return i
  50. def add_content(lines, i, content, add_trailing_line):
  51. if lines[i - 1] == "":
  52. lines[i - 1] = content
  53. else:
  54. i = add_line(lines, i, content)
  55. if add_trailing_line:
  56. i = add_line(lines, i, "")
  57. return i
  58. def add_symbol_to_oldnames(header, oldname, newname):
  59. file = (SDL_INCLUDE_DIR / "SDL_oldnames.h")
  60. lines = file.read_text().splitlines()
  61. mode = 0
  62. i = 0
  63. while i < len(lines):
  64. line = lines[i]
  65. if line == "#ifdef SDL_ENABLE_OLD_NAMES":
  66. if mode == 0:
  67. mode = 1
  68. section = ("/* ##%s */" % header)
  69. section_added = False
  70. content = ("#define %s %s" % (oldname, newname))
  71. content_added = False
  72. else:
  73. raise Exception("add_symbol_to_oldnames(): expected mode 0")
  74. elif line == "#else /* !SDL_ENABLE_OLD_NAMES */":
  75. if mode == 1:
  76. if not section_added:
  77. i = add_line(lines, i, section)
  78. if not content_added:
  79. i = add_content(lines, i, content, True)
  80. mode = 2
  81. section = ("/* ##%s */" % header)
  82. section_added = False
  83. content = ("#define %s %s_renamed_%s" % (oldname, oldname, newname))
  84. content_added = False
  85. else:
  86. raise Exception("add_symbol_to_oldnames(): expected mode 1")
  87. elif line == "#endif /* SDL_ENABLE_OLD_NAMES */":
  88. if mode == 2:
  89. if not section_added:
  90. i = add_line(lines, i, section)
  91. if not content_added:
  92. i = add_content(lines, i, content, True)
  93. mode = 3
  94. else:
  95. raise Exception("add_symbol_to_oldnames(): expected mode 2")
  96. elif line != "" and (mode == 1 or mode == 2):
  97. if line.startswith("/* ##"):
  98. if section_added:
  99. if not content_added:
  100. i = add_content(lines, i, content, True)
  101. content_added = True
  102. elif line == section:
  103. section_added = True
  104. elif section < line:
  105. i = add_line(lines, i, section)
  106. section_added = True
  107. i = add_content(lines, i, content, True)
  108. content_added = True
  109. elif line != "" and section_added and not content_added:
  110. if content == line:
  111. content_added = True
  112. elif content < line:
  113. i = add_content(lines, i, content, False)
  114. content_added = True
  115. i += 1
  116. file.write_text("\n".join(lines) + "\n")
  117. def add_symbol_to_migration(header, symbol_type, oldname, newname):
  118. file = (SDL_ROOT / "docs/README-migration.md")
  119. lines = file.read_text().splitlines()
  120. section = ("## %s" % header)
  121. section_added = False
  122. note = ("The following %ss have been renamed:" % symbol_type)
  123. note_added = False
  124. content = ("* %s -> %s" % (oldname, newname))
  125. content_added = False
  126. mode = 0
  127. i = 0
  128. while i < len(lines):
  129. line = lines[i]
  130. if line.startswith("##") and line.endswith(".h"):
  131. if line == section:
  132. section_added = True
  133. elif section < line:
  134. break
  135. elif section_added and not note_added:
  136. if note == line:
  137. note_added = True
  138. elif note_added and not content_added:
  139. if content == line:
  140. content_added = True
  141. elif line == "" or content < line:
  142. i = add_line(lines, i, content)
  143. content_added = True
  144. i += 1
  145. if not section_added:
  146. i = add_line(lines, i, section)
  147. i = add_line(lines, i, "")
  148. if not note_added:
  149. i = add_line(lines, i, note)
  150. if not content_added:
  151. i = add_content(lines, i, content, True)
  152. file.write_text("\n".join(lines) + "\n")
  153. def add_symbol_to_whatsnew(symbol_type, oldname, newname):
  154. file = (SDL_ROOT / "WhatsNew.txt")
  155. lines = file.read_text().splitlines()
  156. note = ("* The following %ss have been renamed:" % symbol_type)
  157. note_added = False
  158. content = (" * %s -> %s" % (oldname, newname))
  159. content_added = False
  160. mode = 0
  161. i = 0
  162. while i < len(lines):
  163. line = lines[i]
  164. if not note_added:
  165. if note == line:
  166. note_added = True
  167. elif not content_added:
  168. if content == line:
  169. content_added = True
  170. elif not line.startswith(" *") or content < line:
  171. i = add_line(lines, i, content)
  172. content_added = True
  173. i += 1
  174. if not note_added:
  175. i = add_line(lines, i, note)
  176. if not content_added:
  177. i = add_line(lines, i, content)
  178. file.write_text("\r\n".join(lines) + "\r\n")
  179. if __name__ == '__main__':
  180. parser = argparse.ArgumentParser()
  181. parser.add_argument('--code-only', action='store_true')
  182. parser.add_argument('header');
  183. parser.add_argument('type', choices=['enum', 'function', 'macro', 'structure']);
  184. parser.add_argument('oldname');
  185. parser.add_argument('newname');
  186. args = parser.parse_args()
  187. try:
  188. main()
  189. except Exception as e:
  190. print(e)
  191. exit(-1)
  192. exit(0)