rename.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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', 'docs']:
  29. replace_symbol_recursive(SDL_ROOT / dir, pattern, args.newname)
  30. add_symbol_to_oldnames(header.name, args.oldname, args.newname)
  31. add_symbol_to_migration(header.name, args.type, args.oldname, args.newname)
  32. add_symbol_to_whatsnew(args.type, args.oldname, args.newname)
  33. def replace_symbol_recursive(path, pattern, replacement):
  34. for entry in path.glob("*"):
  35. if entry.is_dir():
  36. replace_symbol_recursive(entry, pattern, replacement)
  37. elif not entry.name.endswith((".bmp", ".cur", ".dat", ".icns", ".png", ".strings", ".swp", ".wav")) and \
  38. entry.name != "utf8.txt":
  39. print("Processing %s" % entry)
  40. with entry.open('r', encoding='UTF-8', newline='') as rfp:
  41. contents = pattern.sub(replacement, rfp.read())
  42. with entry.open('w', encoding='UTF-8', newline='') as wfp:
  43. wfp.write(contents)
  44. def add_line(lines, i, section):
  45. lines.insert(i, section)
  46. i += 1
  47. return i
  48. def add_content(lines, i, content, add_trailing_line):
  49. if lines[i - 1] == "":
  50. lines[i - 1] = content
  51. else:
  52. i = add_line(lines, i, content)
  53. if add_trailing_line:
  54. i = add_line(lines, i, "")
  55. return i
  56. def add_symbol_to_oldnames(header, oldname, newname):
  57. file = (SDL_INCLUDE_DIR / "SDL_oldnames.h")
  58. lines = file.read_text().splitlines()
  59. mode = 0
  60. i = 0
  61. while i < len(lines):
  62. line = lines[i]
  63. if line == "#ifdef SDL_ENABLE_OLD_NAMES":
  64. if mode == 0:
  65. mode = 1
  66. section = ("/* ##%s */" % header)
  67. section_added = False
  68. content = ("#define %s %s" % (oldname, newname))
  69. content_added = False
  70. else:
  71. raise Exception("add_symbol_to_oldnames(): expected mode 0")
  72. elif line == "#else /* !SDL_ENABLE_OLD_NAMES */":
  73. if mode == 1:
  74. if not section_added:
  75. i = add_line(lines, i, section)
  76. if not content_added:
  77. i = add_content(lines, i, content, True)
  78. mode = 2
  79. section = ("/* ##%s */" % header)
  80. section_added = False
  81. content = ("#define %s %s_renamed_%s" % (oldname, oldname, newname))
  82. content_added = False
  83. else:
  84. raise Exception("add_symbol_to_oldnames(): expected mode 1")
  85. elif line == "#endif /* SDL_ENABLE_OLD_NAMES */":
  86. if mode == 2:
  87. if not section_added:
  88. i = add_line(lines, i, section)
  89. if not content_added:
  90. i = add_content(lines, i, content, True)
  91. mode = 3
  92. else:
  93. raise Exception("add_symbol_to_oldnames(): expected mode 2")
  94. elif line != "" and (mode == 1 or mode == 2):
  95. if line.startswith("/* ##"):
  96. if section_added:
  97. if not content_added:
  98. i = add_content(lines, i, content, True)
  99. content_added = True
  100. elif line == section:
  101. section_added = True
  102. elif section < line:
  103. i = add_line(lines, i, section)
  104. section_added = True
  105. i = add_content(lines, i, content, True)
  106. content_added = True
  107. elif line != "" and section_added and not content_added:
  108. if content == line:
  109. content_added = True
  110. elif content < line:
  111. i = add_content(lines, i, content, False)
  112. content_added = True
  113. i += 1
  114. file.write_text("\n".join(lines) + "\n")
  115. def add_symbol_to_migration(header, symbol_type, oldname, newname):
  116. file = (SDL_ROOT / "docs/README-migration.md")
  117. lines = file.read_text().splitlines()
  118. section = ("## %s" % header)
  119. section_added = False
  120. note = ("The following %ss have been renamed:" % symbol_type)
  121. note_added = False
  122. content = ("* %s -> %s" % (oldname, newname))
  123. content_added = False
  124. mode = 0
  125. i = 0
  126. while i < len(lines):
  127. line = lines[i]
  128. if line.startswith("##") and line.endswith(".h"):
  129. if line == section:
  130. section_added = True
  131. elif section < line:
  132. break
  133. elif section_added and not note_added:
  134. if note == line:
  135. note_added = True
  136. elif note_added and not content_added:
  137. if content == line:
  138. content_added = True
  139. elif line == "" or content < line:
  140. i = add_line(lines, i, content)
  141. content_added = True
  142. i += 1
  143. if not section_added:
  144. i = add_line(lines, i, section)
  145. i = add_line(lines, i, "")
  146. if not note_added:
  147. i = add_line(lines, i, note)
  148. if not content_added:
  149. i = add_content(lines, i, content, True)
  150. file.write_text("\n".join(lines) + "\n")
  151. def add_symbol_to_whatsnew(symbol_type, oldname, newname):
  152. file = (SDL_ROOT / "WhatsNew.txt")
  153. lines = file.read_text().splitlines()
  154. note = ("* The following %ss have been renamed:" % symbol_type)
  155. note_added = False
  156. content = (" * %s -> %s" % (oldname, newname))
  157. content_added = False
  158. mode = 0
  159. i = 0
  160. while i < len(lines):
  161. line = lines[i]
  162. if not note_added:
  163. if note == line:
  164. note_added = True
  165. elif not content_added:
  166. if content == line:
  167. content_added = True
  168. elif not line.startswith(" *") or content < line:
  169. i = add_line(lines, i, content)
  170. content_added = True
  171. i += 1
  172. if not note_added:
  173. i = add_line(lines, i, note)
  174. if not content_added:
  175. i = add_line(lines, i, content)
  176. file.write_text("\r\n".join(lines) + "\r\n")
  177. if __name__ == '__main__':
  178. parser = argparse.ArgumentParser()
  179. parser.add_argument('header');
  180. parser.add_argument('type', choices=['function', 'enum']);
  181. parser.add_argument('oldname');
  182. parser.add_argument('newname');
  183. args = parser.parse_args()
  184. try:
  185. main()
  186. except Exception as e:
  187. print(e)
  188. exit(-1)
  189. exit(0)