maintainer_update.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/env python
  2. """rtl_433 maintainer updates to build files and docs."""
  3. from __future__ import print_function
  4. import os
  5. import subprocess
  6. import glob
  7. import re
  8. def require_clean_work_tree():
  9. """Check if the working tree is clean, exit otherwise."""
  10. clean = not len(subprocess.check_output(["git", "diff", "--stat"]))
  11. if not clean:
  12. print("Please commit or stash your changes.")
  13. exit(1)
  14. def grep_lines(pattern, filepath):
  15. with open(filepath, 'r') as file:
  16. filedata = file.read()
  17. regex = re.compile(pattern)
  18. return regex.findall(filedata)
  19. def replace_text(pattern, repl, filepath):
  20. with open(filepath, 'r') as file:
  21. filedata = file.read()
  22. regex = re.compile(pattern)
  23. filedata = regex.sub(repl, filedata)
  24. with open(filepath, 'w') as file:
  25. file.write(filedata)
  26. def replace_block(from_pattern, to_pattern, repl, filepath):
  27. with open(filepath, 'r') as file:
  28. filedata = file.read()
  29. pattern = '(?ms)(' + from_pattern + ').*?(' + to_pattern + ')'
  30. repl = r'\g<1>%s\g<2>' % repl
  31. regex = re.compile(pattern)
  32. filedata = regex.sub(repl, filedata)
  33. with open(filepath, 'w') as file:
  34. file.write(filedata)
  35. def get_help_text(option):
  36. try:
  37. help_text = subprocess.check_output(
  38. ["./build/src/rtl_433", "-c", "0", option], stderr=subprocess.STDOUT)
  39. except subprocess.CalledProcessError as e:
  40. help_text = e.output
  41. # trim help text
  42. help_text = re.sub(r'(?s).*Usage:', '', help_text)
  43. help_text = re.sub(r'(?s).*option requires an argument -- .', '', help_text)
  44. # help_text = re.sub(r'(?m)^\s*=\s+(.*)\s+=\s*$', r'### \1', help_text)
  45. return help_text
  46. def markup_man_text(help_text):
  47. # sub section headings
  48. help_text = re.sub(r'(?m)^\s*=\s+(.*)\s+=\s*$', r'.SS "\1"', help_text)
  49. # indented lines
  50. help_text = re.sub(r'(?m)^\t(.*)$', r'.RS\n\1\n.RE', help_text)
  51. # options
  52. help_text = re.sub(r'(?m)^\s*\[(\S*)(.*)\]\s*(.*)$',
  53. r'.TP\n[ \\\\fB\1\\\\fI\2\\\\fP ]\n\3', help_text)
  54. # fix hyphens
  55. help_text = re.sub(r'-', '\\-', help_text)
  56. # fix quotes
  57. help_text = re.sub(r'(?m)^\'', ' \'', help_text)
  58. return help_text
  59. # Make sure we run from the top dir
  60. topdir = os.path.dirname(os.path.abspath(__file__))
  61. os.chdir(topdir)
  62. # Only ever run on a clean working tree
  63. require_clean_work_tree()
  64. # glob all src and device files
  65. os.chdir("src")
  66. src_files = sorted(glob.glob('*.c'))
  67. print("src_files =", src_files)
  68. device_files = sorted(glob.glob('devices/*.c'))
  69. print("device_files =", device_files)
  70. os.chdir("..")
  71. # glob all includes
  72. os.chdir("include")
  73. include_files = sorted(glob.glob('*.h'))
  74. print("include_files =", include_files)
  75. os.chdir("..")
  76. # grep all r_devices
  77. r_devices = [grep_lines(r'(?m)^r_device\s*(.*?)\s*=.*',
  78. os.path.join("src", p)) for p in device_files]
  79. r_devices = [item for sublist in r_devices for item in sublist]
  80. print("r_devices =", r_devices)
  81. # count r_devices, correct for 'new_template' being used six times
  82. r_devices_used = len(r_devices) + 5
  83. # README.md
  84. # Replace everything between ``` with help output.
  85. repl = '\n' + get_help_text('-h') + '\n'
  86. repl += get_help_text('-R') + '\n'
  87. repl += get_help_text('-d') + '\n'
  88. repl += get_help_text('-g') + '\n'
  89. repl += get_help_text('-X') + '\n'
  90. repl += get_help_text('-F') + '\n'
  91. repl += get_help_text('-M') + '\n'
  92. repl += get_help_text('-r') + '\n'
  93. repl += get_help_text('-w') + '\n'
  94. replace_block(r'```',
  95. r'```', repl, 'README.md')
  96. # MAN pages
  97. repl = markup_man_text(repl)
  98. replace_block(r'\.\\" body',
  99. r'\.\\" end', '\n'+repl, 'man/man1/rtl_433.1')
  100. # src/CMakeLists.txt
  101. repl = src_files + device_files
  102. repl.remove('rtl_433.c') # exclude apps from lib sources
  103. repl = '\n ' + ('\n '.join(repl)) + '\n'
  104. replace_block(r'add_library\(r_433 STATIC$',
  105. r'^\)', repl, 'src/CMakeLists.txt')
  106. # src/Makefile.am
  107. # replace everything between 'rtl_433_SOURCES = ' and \n\n with *.c and devices/*.c from src
  108. repl = src_files + device_files
  109. repl = (' \\\n '.join(repl)) + '\n'
  110. replace_block(r'rtl_433_SOURCES = ',
  111. r'^$', repl, 'src/Makefile.am')
  112. # include/rtl_433.h
  113. # update '#define MAX_PROTOCOLS ?' with actual count
  114. #replace_text(r'(?m)(#define\s+MAX_PROTOCOLS\s+)\d+',
  115. # r'\g<1>%d' % r_devices_used, 'include/rtl_433.h')
  116. # include/rtl_433_devices.h
  117. # check that everything between '#define DEVICES' and \n\n with DECL(device_name) matches r_devices
  118. # TODO: implement the check...
  119. # vs15/rtl_433.vcxproj
  120. # <ItemGroup>
  121. # <ClInclude Include="..\include\baseband.h" />
  122. # ...
  123. # </ItemGroup>
  124. repl = (r'" />\n <ClInclude Include="..\\include\\'.join(include_files))
  125. replace_block(r'^ <ItemGroup>\n <ClInclude Include="..\\include\\',
  126. r'" />\n <ClInclude Include="..\\src\\getopt', repl, 'vs15/rtl_433.vcxproj')
  127. # <ItemGroup>
  128. # <ClCompile Include="..\src\baseband.c" />
  129. # ...
  130. # </ItemGroup>
  131. repl = src_files + device_files
  132. repl = [p.replace('/', r'\\') for p in repl]
  133. repl = (r'" />\n <ClCompile Include="..\\src\\'.join(repl))
  134. replace_block(r'^ <ItemGroup>\n <ClCompile Include="..\\src\\',
  135. r'" />\n <ClCompile Include="..\\src\\getopt', repl, 'vs15/rtl_433.vcxproj')
  136. # vs15/rtl_433.vcxproj.filters
  137. # <ItemGroup>
  138. # <ClInclude Include="..\include\baseband.h">
  139. # <Filter>Header Files</Filter>
  140. # </ClInclude>
  141. # ...
  142. # </ItemGroup>
  143. # "Header Files"
  144. repl = (r'">\n <Filter>Header Files</Filter>\n </ClInclude>\n <ClInclude Include="..\\include\\'.join(include_files))
  145. replace_block(r'^ <ItemGroup>\n <ClInclude Include="..\\include\\',
  146. r'">\n <Filter>Header Files</Filter>\n </ClInclude>\n <ClInclude Include="..\\src\\getopt', repl, 'vs15/rtl_433.vcxproj.filters')
  147. # "Source Files"
  148. repl = (r'">\n <Filter>Source Files</Filter>\n </ClCompile>\n <ClCompile Include="..\\src\\'.join(src_files))
  149. replace_block(r'^ <ItemGroup>\n <ClCompile Include="..\\src\\',
  150. r'">\n <Filter>Source Files</Filter>\n </ClCompile>\n <ClCompile Include="..\\src\\getopt', repl, 'vs15/rtl_433.vcxproj.filters')
  151. # "Source Files\devices"
  152. repl = [p.replace('devices/', '') for p in device_files]
  153. repl = (r'">\n <Filter>Source Files\\devices</Filter>\n </ClCompile>\n <ClCompile Include="..\\src\\devices\\'.join(repl))
  154. replace_block(r'^ <ClCompile Include="..\\src\\devices\\',
  155. r'">\n <Filter>Source Files\\devices</Filter>\n </ClCompile>\n </ItemGroup>', repl, 'vs15/rtl_433.vcxproj.filters')