make.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #!/usr/bin/python
  2. ###
  3. ### Build script for the la-warch app. This script is responsible
  4. ### for building app from source, and config. Config file is
  5. ###
  6. ### ./config.json
  7. ###
  8. ### This file has documentation, with options that could be change to
  9. ### make this app more flexible for the end users.
  10. if not __name__ == "__main__":
  11. print("This is build system. Can be only executed as app.")
  12. exit(-2)
  13. import json
  14. import pathlib
  15. import shutil
  16. import subprocess
  17. import datetime
  18. # Current release
  19. release = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
  20. # Root project directory
  21. root = pathlib.Path("./")
  22. # This is root source dir
  23. source = root / pathlib.Path("./source/")
  24. # Sources with types of content
  25. script_source = source / pathlib.Path("./scripts/")
  26. sass_source = source / pathlib.Path("./theme/")
  27. static_files = source / pathlib.Path("./static/")
  28. templates = source / pathlib.Path("./templates/")
  29. # Specific files, like loaders, main view, etc.
  30. app_view_file = templates / pathlib.Path("view.html")
  31. script_loader_file = script_source / pathlib.Path("loader.js")
  32. sass_loader_file = sass_source / pathlib.Path("loader.sass")
  33. sass_loading_screen_file = sass_source / pathlib.Path("loading-screen.sass")
  34. config = root / pathlib.Path("config.json")
  35. # Build dir
  36. build = root / pathlib.Path("./build/")
  37. # Result specific files
  38. app_view_result_file = build / pathlib.Path("index.html")
  39. script_loader_result_file = build / pathlib.Path("bundle.js")
  40. sass_loader_result_file = build / pathlib.Path("bundle.css")
  41. sass_loading_screen_tmp_file = build / pathlib.Path("loading-screen.css")
  42. static_files_output = build / pathlib.Path("static")
  43. # Checking that directories exists
  44. if not source.is_dir():
  45. print("Source directory not exists.")
  46. exit(-1)
  47. if not script_source.is_dir():
  48. print("Script source directory not exists.")
  49. exit(-1)
  50. if not sass_source.is_dir():
  51. print("Sass source director not exists.")
  52. exit(-1)
  53. if not static_files.is_dir():
  54. print("Static files directory not exists.")
  55. exit(-1)
  56. if not templates.is_dir():
  57. print("Templates directory not exists.")
  58. exit(-1)
  59. # Checking files
  60. if not app_view_file.is_file():
  61. print("App view file not exists.")
  62. exit(-1)
  63. # Check config file
  64. if not config.is_file():
  65. print("App config file not exists.")
  66. exit(-1)
  67. # Check script loader file
  68. if not script_loader_file.is_file():
  69. print("Script loader file not exists.")
  70. exit(-1)
  71. # Check SASS loader file
  72. if not sass_loader_file.is_file():
  73. print("SASS loader file not exists.")
  74. exit(-1)
  75. # Check that SASS loading screen file exists
  76. if not sass_loading_screen_file.is_file():
  77. print("SASS loading screen file not exists.")
  78. exit(-1)
  79. # Prepare result directory
  80. if build.is_dir():
  81. shutil.rmtree(build)
  82. build.mkdir()
  83. # Parse config json
  84. try:
  85. with config.open() as handle:
  86. config = json.loads(handle.read())
  87. except event:
  88. print(str(event))
  89. print("Can not parse config file.")
  90. exit(-1)
  91. def get_config_section(
  92. name: str,
  93. alt: str | int | float | list | None = None
  94. ) -> str | int | float | list:
  95. '''
  96. This get section from root config file, or raise exception when section
  97. not exists, and alt is set to None. When alt is provided, and section
  98. not exists then return alt. If section exists, then return section.
  99. Parameters:
  100. name (str): Name of the section
  101. alt (str | int | float | list | None) = None: Alternative value
  102. Returns:
  103. (str | int | flaot | list): Value of the section
  104. '''
  105. global config
  106. if name in config:
  107. return config[name]
  108. if alt is not None:
  109. return alt
  110. print("Not found section \"" + name + "\" in config.")
  111. exit(-2)
  112. def compile(*command: list) -> None:
  113. '''
  114. This function execute command, and when command not exit without
  115. error code, that mean not return 0, then it print STDOUT and STDERR
  116. from the command.
  117. Parameters:
  118. command (list): Command as list of str
  119. '''
  120. result = subprocess.run(command, capture_output = True)
  121. if result.returncode == 0:
  122. return
  123. print(result.stdout.decode("UTF-8"))
  124. print(result.stderr.decode("UTF-8"))
  125. print("Compilation end with error.")
  126. exit(-5)
  127. # Rendering app view
  128. from source.make.render import render
  129. from source.make.dom import link, script, style
  130. app_view_render = render(app_view_file)
  131. # App view use HTML description as replace tags
  132. app_view_render.start_tag = "{{"
  133. app_view_render.stop_tag = "}}"
  134. view_params = get_config_section("view-params")
  135. # Replace all elements from view-params config section
  136. for param in view_params.keys():
  137. content = view_params[param]
  138. if type(content) is str:
  139. app_view_render.add(param, content)
  140. continue
  141. if type(content) is float or type(content) is int:
  142. app_view_render.add(param, str(content))
  143. continue
  144. print("Param " + param + " not contain string or number.")
  145. exit(-3)
  146. # Compile loading screen sass file
  147. compile(
  148. "sass",
  149. "--sourcemap=none",
  150. "-t compressed",
  151. str(sass_loading_screen_file),
  152. str(sass_loading_screen_tmp_file)
  153. )
  154. # Open compiled tmp file, add it to view, and drop tmp file
  155. loading_screen = style()
  156. with sass_loading_screen_tmp_file.open() as handle:
  157. loading_screen.content = handle.read()
  158. sass_loading_screen_tmp_file.unlink()
  159. # Generating tags
  160. sass_link = link()
  161. sass_link.rel = "stylesheet"
  162. sass_link.type = "text/css"
  163. sass_link.href = "./" + sass_loader_result_file.name + "?version=" + release
  164. js_script = script()
  165. js_script.src = "./" + script_loader_result_file.name + "?version=" + release
  166. bundle_items = (
  167. sass_link.render() +
  168. js_script.render() +
  169. loading_screen.render()
  170. )
  171. # Add bundle items tags
  172. app_view_render.add("bundle_items", bundle_items)
  173. # Render and save app view
  174. app_view = app_view_render.finalize()
  175. try:
  176. with app_view_result_file.open("w") as handle:
  177. handle.write(app_view)
  178. except event:
  179. print("Can not save app view.")
  180. print(str(event))
  181. exit(-4)
  182. # Bundle JS script source
  183. compile(
  184. "esbuild",
  185. str(script_loader_file),
  186. "--bundle",
  187. "--outfile=" + str(script_loader_result_file)
  188. )
  189. # Bundle SASS themes source
  190. compile(
  191. "sass",
  192. "--sourcemap=none",
  193. "-t compressed",
  194. str(sass_loader_file),
  195. str(sass_loader_result_file)
  196. )
  197. # Copy static folder
  198. compile(
  199. "cp",
  200. "-r",
  201. str(static_files),
  202. str(static_files_output)
  203. )
  204. print("Build success!")