editor_builders.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. """Functions used to generate source files during build time"""
  2. import os
  3. import os.path
  4. import subprocess
  5. import tempfile
  6. import uuid
  7. import methods
  8. def doc_data_class_path_builder(target, source, env):
  9. paths = dict(sorted(source[0].read().items()))
  10. data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
  11. with methods.generated_wrapper(str(target[0])) as file:
  12. file.write(
  13. f"""\
  14. struct _DocDataClassPath {{
  15. const char *name;
  16. const char *path;
  17. }};
  18. inline constexpr int _doc_data_class_path_count = {len(paths)};
  19. inline constexpr _DocDataClassPath _doc_data_class_paths[{len(paths) + 1}] = {{
  20. {data}
  21. {{nullptr, nullptr}},
  22. }};
  23. """
  24. )
  25. def register_exporters_builder(target, source, env):
  26. platforms = source[0].read()
  27. exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
  28. exp_reg = "\n\t".join([f"register_{p}_exporter();" for p in platforms])
  29. exp_type = "\n\t".join([f"register_{p}_exporter_types();" for p in platforms])
  30. with methods.generated_wrapper(str(target[0])) as file:
  31. file.write(
  32. f"""\
  33. #include "register_exporters.h"
  34. {exp_inc}
  35. void register_exporters() {{
  36. {exp_reg}
  37. }}
  38. void register_exporter_types() {{
  39. {exp_type}
  40. }}
  41. """
  42. )
  43. def make_doc_header(target, source, env):
  44. buffer = b"".join([methods.get_buffer(src) for src in map(str, source)])
  45. decomp_size = len(buffer)
  46. buffer = methods.compress_buffer(buffer)
  47. with methods.generated_wrapper(str(target[0])) as file:
  48. file.write(f"""\
  49. inline constexpr const char *_doc_data_hash = "{hash(buffer)}";
  50. inline constexpr int _doc_data_compressed_size = {len(buffer)};
  51. inline constexpr int _doc_data_uncompressed_size = {decomp_size};
  52. inline constexpr const unsigned char _doc_data_compressed[] = {{
  53. {methods.format_buffer(buffer, 1)}
  54. }};
  55. """)
  56. def make_translations_header(target, source, env):
  57. category = os.path.basename(str(target[0])).split("_")[0]
  58. sorted_paths = sorted([src.abspath for src in source], key=lambda path: os.path.splitext(os.path.basename(path))[0])
  59. xl_names = []
  60. msgfmt = env.Detect("msgfmt")
  61. if not msgfmt:
  62. methods.print_warning("msgfmt not found, using .po files instead of .mo")
  63. with methods.generated_wrapper(str(target[0])) as file:
  64. for path in sorted_paths:
  65. name = os.path.splitext(os.path.basename(path))[0]
  66. # msgfmt erases non-translated messages, so avoid using it if exporting the POT.
  67. if msgfmt and name != category:
  68. mo_path = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex + ".mo")
  69. cmd = f"{msgfmt} {path} --no-hash -o {mo_path}"
  70. try:
  71. subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
  72. buffer = methods.get_buffer(mo_path)
  73. except OSError as e:
  74. methods.print_warning(
  75. "msgfmt execution failed, using .po file instead of .mo: path=%r; [%s] %s"
  76. % (path, e.__class__.__name__, e)
  77. )
  78. buffer = methods.get_buffer(path)
  79. finally:
  80. try:
  81. if os.path.exists(mo_path):
  82. os.remove(mo_path)
  83. except OSError as e:
  84. # Do not fail the entire build if it cannot delete a temporary file.
  85. methods.print_warning(
  86. "Could not delete temporary .mo file: path=%r; [%s] %s" % (mo_path, e.__class__.__name__, e)
  87. )
  88. else:
  89. buffer = methods.get_buffer(path)
  90. if name == category:
  91. name = "source"
  92. decomp_size = len(buffer)
  93. buffer = methods.compress_buffer(buffer)
  94. file.write(f"""\
  95. inline constexpr const unsigned char _{category}_translation_{name}_compressed[] = {{
  96. {methods.format_buffer(buffer, 1)}
  97. }};
  98. """)
  99. xl_names.append([name, len(buffer), decomp_size])
  100. file.write(f"""\
  101. struct {category.capitalize()}TranslationList {{
  102. const char* lang;
  103. int comp_size;
  104. int uncomp_size;
  105. const unsigned char* data;
  106. }};
  107. inline constexpr {category.capitalize()}TranslationList _{category}_translations[] = {{
  108. """)
  109. for x in xl_names:
  110. file.write(f'\t{{ "{x[0]}", {x[1]}, {x[2]}, _{category}_translation_{x[0]}_compressed }},\n')
  111. file.write("""\
  112. { nullptr, 0, 0, nullptr },
  113. };
  114. """)