leveldb_patch.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. from typing import Iterable, Sequence
  23. def main() -> None:
  24. arg_parser = argparse.ArgumentParser()
  25. arg_parser.add_argument("--snappy-source-dir", required=True)
  26. arg_parser.add_argument("--snappy-binary-dir", required=True)
  27. parsed_args = arg_parser.parse_args()
  28. del arg_parser
  29. snappy_source_dir = pathlib.Path(parsed_args.snappy_source_dir)
  30. snappy_binary_dir = pathlib.Path(parsed_args.snappy_binary_dir)
  31. del parsed_args
  32. cmakelists_txt_file = pathlib.Path("CMakeLists.txt")
  33. with cmakelists_txt_file.open("rt", encoding="utf8") as f:
  34. lines = tuple(f)
  35. patcher = CMakeListsPatcher(
  36. lines,
  37. os.path.abspath(__file__),
  38. snappy_source_dir,
  39. snappy_binary_dir,
  40. )
  41. patched_lines = tuple(patcher.patch())
  42. with cmakelists_txt_file.open("wt", encoding="utf8") as f:
  43. f.writelines(patched_lines)
  44. @dataclasses.dataclass(frozen=True)
  45. class LineComponents:
  46. full: str
  47. indent: str
  48. line: str
  49. eol: str
  50. class CMakeListsPatcher:
  51. SNAPPY_DETECT_LINE = \
  52. """check_library_exists(snappy snappy_compress "" HAVE_SNAPPY)"""
  53. SNAPPY_INCLUDE_LINE = \
  54. "target_include_directories(leveldb"
  55. SNAPPY_LINK_LINE = \
  56. "target_link_libraries(leveldb snappy)"
  57. def __init__(
  58. self,
  59. lines: Sequence[str],
  60. script_name: str,
  61. snappy_source_dir: pathlib.Path,
  62. snappy_binary_dir: pathlib.Path) -> None:
  63. self.i = 0
  64. self.lines = lines
  65. self.script_name = script_name
  66. self.snappy_source_dir_str = snappy_source_dir.as_posix()
  67. self.snappy_binary_dir_str = snappy_binary_dir.as_posix()
  68. def patch(self) -> Iterable[str]:
  69. while self.i < len(self.lines):
  70. full_line = self.lines[self.i]
  71. line = self._split_line(full_line)
  72. self.i += 1
  73. if line.line == self.SNAPPY_DETECT_LINE:
  74. yield from self._on_snappy_detect_line(line)
  75. elif line.line == self.SNAPPY_INCLUDE_LINE:
  76. yield full_line
  77. yield from self._on_leveldb_include_start()
  78. elif line.line == self.SNAPPY_LINK_LINE:
  79. yield from self._on_leveldb_snappy_link_line(line)
  80. else:
  81. yield full_line
  82. def _begin_mod_line(self, mod_name: str) -> str:
  83. return f"# BEGIN: {mod_name} modification by {self.script_name}"
  84. def _end_mod_line(self, mod_name: str) -> str:
  85. return f"# END: {mod_name} modification by {self.script_name}"
  86. def _on_snappy_detect_line(self, line: LineComponents) -> Iterable[str]:
  87. yield self._begin_mod_line("snappy_detect_line") + line.eol
  88. yield line.indent + "# " + line.line + line.eol
  89. yield line.indent + """set(HAVE_SNAPPY ON CACHE BOOL "")""" + line.eol
  90. yield self._end_mod_line("snappy_detect_line") + line.eol
  91. def _on_leveldb_include_start(self) -> Iterable[str]:
  92. line1 = self._split_line(self.lines[self.i])
  93. line2 = self._split_line(self.lines[self.i + 1])
  94. begin_mod_line = self._begin_mod_line("leveldb_include_start")
  95. if line1.line == begin_mod_line:
  96. return
  97. yield begin_mod_line + line1.eol
  98. yield line1.indent + "PRIVATE" + line1.eol
  99. yield line2.indent + self.snappy_source_dir_str + line2.eol
  100. yield line2.indent + self.snappy_binary_dir_str + line2.eol
  101. yield self._end_mod_line("leveldb_include_start") + line1.eol
  102. def _on_leveldb_snappy_link_line(self, line: LineComponents) -> Iterable[str]:
  103. yield self._begin_mod_line("leveldb_snappy_link_line") + line.eol
  104. yield line.indent + "# " + line.line + line.eol
  105. yield line.indent + f"target_link_libraries(leveldb Snappy::Snappy)" + line.eol
  106. yield self._end_mod_line("leveldb_snappy_link_line") + line.eol
  107. def _split_line(self, line: str) -> LineComponents:
  108. line_rstripped = line.rstrip()
  109. eol = line[len(line_rstripped):]
  110. line_stripped = line_rstripped.strip()
  111. indent = line_rstripped[:len(line_rstripped) - len(line_stripped)]
  112. return LineComponents(full=line, indent=indent, line=line_stripped, eol=eol)
  113. class LeveDbPatchException(Exception):
  114. pass
  115. if __name__ == "__main__":
  116. main()