leveldb_patch.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # Copyright 2022 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """
  15. Modify the CMakeLists.txt from LevelDb to staticly link Snappy compression
  16. support.
  17. """
  18. import argparse
  19. import dataclasses
  20. import os
  21. import pathlib
  22. import subprocess
  23. from typing import Iterable, Sequence
  24. def main() -> None:
  25. arg_parser = argparse.ArgumentParser()
  26. arg_parser.add_argument("--snappy-source-dir", required=True)
  27. arg_parser.add_argument("--snappy-binary-dir", required=True)
  28. arg_parser.add_argument("--additional-patch-file", required=False)
  29. parsed_args = arg_parser.parse_args()
  30. del arg_parser
  31. snappy_source_dir = pathlib.Path(parsed_args.snappy_source_dir)
  32. snappy_binary_dir = pathlib.Path(parsed_args.snappy_binary_dir)
  33. additional_patch_file = parsed_args.additional_patch_file
  34. del parsed_args
  35. cmakelists_txt_file = pathlib.Path("CMakeLists.txt")
  36. with cmakelists_txt_file.open("rt", encoding="utf8") as f:
  37. lines = tuple(f)
  38. patcher = CMakeListsPatcher(
  39. lines,
  40. os.path.abspath(__file__),
  41. snappy_source_dir,
  42. snappy_binary_dir,
  43. )
  44. patched_lines = tuple(patcher.patch())
  45. with cmakelists_txt_file.open("wt", encoding="utf8") as f:
  46. f.writelines(patched_lines)
  47. if additional_patch_file:
  48. subprocess.run(['git', 'apply', '-v', additional_patch_file],
  49. check=True)
  50. @dataclasses.dataclass(frozen=True)
  51. class LineComponents:
  52. full: str
  53. indent: str
  54. line: str
  55. eol: str
  56. class CMakeListsPatcher:
  57. SNAPPY_DETECT_LINE = \
  58. """check_library_exists(snappy snappy_compress "" HAVE_SNAPPY)"""
  59. SNAPPY_INCLUDE_LINE = \
  60. "target_include_directories(leveldb"
  61. SNAPPY_LINK_LINE = \
  62. "target_link_libraries(leveldb snappy)"
  63. def __init__(
  64. self,
  65. lines: Sequence[str],
  66. script_name: str,
  67. snappy_source_dir: pathlib.Path,
  68. snappy_binary_dir: pathlib.Path) -> None:
  69. self.i = 0
  70. self.lines = lines
  71. self.script_name = script_name
  72. self.snappy_source_dir_str = snappy_source_dir.as_posix()
  73. self.snappy_binary_dir_str = snappy_binary_dir.as_posix()
  74. def patch(self) -> Iterable[str]:
  75. while self.i < len(self.lines):
  76. full_line = self.lines[self.i]
  77. line = self._split_line(full_line)
  78. self.i += 1
  79. if line.line == self.SNAPPY_DETECT_LINE:
  80. yield from self._on_snappy_detect_line(line)
  81. elif line.line == self.SNAPPY_INCLUDE_LINE:
  82. yield full_line
  83. yield from self._on_leveldb_include_start()
  84. elif line.line == self.SNAPPY_LINK_LINE:
  85. yield from self._on_leveldb_snappy_link_line(line)
  86. else:
  87. yield full_line
  88. def _begin_mod_line(self, mod_name: str) -> str:
  89. return f"# BEGIN: {mod_name} modification by {self.script_name}"
  90. def _end_mod_line(self, mod_name: str) -> str:
  91. return f"# END: {mod_name} modification by {self.script_name}"
  92. def _on_snappy_detect_line(self, line: LineComponents) -> Iterable[str]:
  93. yield self._begin_mod_line("snappy_detect_line") + line.eol
  94. yield line.indent + "# " + line.line + line.eol
  95. yield line.indent + """set(HAVE_SNAPPY ON CACHE BOOL "")""" + line.eol
  96. yield self._end_mod_line("snappy_detect_line") + line.eol
  97. def _on_leveldb_include_start(self) -> Iterable[str]:
  98. line1 = self._split_line(self.lines[self.i])
  99. line2 = self._split_line(self.lines[self.i + 1])
  100. begin_mod_line = self._begin_mod_line("leveldb_include_start")
  101. if line1.line == begin_mod_line:
  102. return
  103. yield begin_mod_line + line1.eol
  104. yield line1.indent + "PRIVATE" + line1.eol
  105. yield line2.indent + self.snappy_source_dir_str + line2.eol
  106. yield line2.indent + self.snappy_binary_dir_str + line2.eol
  107. yield self._end_mod_line("leveldb_include_start") + line1.eol
  108. def _on_leveldb_snappy_link_line(self, line: LineComponents) -> Iterable[str]:
  109. yield self._begin_mod_line("leveldb_snappy_link_line") + line.eol
  110. yield line.indent + "# " + line.line + line.eol
  111. yield line.indent + f"target_link_libraries(leveldb Snappy::Snappy)" + line.eol
  112. yield self._end_mod_line("leveldb_snappy_link_line") + line.eol
  113. def _split_line(self, line: str) -> LineComponents:
  114. line_rstripped = line.rstrip()
  115. eol = line[len(line_rstripped):]
  116. line_stripped = line_rstripped.strip()
  117. indent = line_rstripped[:len(line_rstripped) - len(line_stripped)]
  118. return LineComponents(full=line, indent=indent, line=line_stripped, eol=eol)
  119. class LeveDbPatchException(Exception):
  120. pass
  121. if __name__ == "__main__":
  122. main()