make.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. output_config = static_files_output / pathlib.Path("config")
  44. # App config directory
  45. app_config = root / pathlib.Path("config/")
  46. app_example_config = root / pathlib.Path("example_config/")
  47. # Check app config
  48. if not app_config.is_dir():
  49. app_config = app_example_config
  50. print("Custom config not found. Using example config.")
  51. if not app_config.is_dir():
  52. print("App example config not exists.")
  53. exit(-1)
  54. # App config files and directories
  55. enviroment = app_config / pathlib.Path("enviroment.json")
  56. rooms = app_config / pathlib.Path("rooms.json")
  57. items = app_config / pathlib.Path("items.json")
  58. textures = app_config / pathlib.Path("textures")
  59. objects = app_config / pathlib.Path("objects")
  60. # Checking config directories
  61. if not enviroment.is_file():
  62. print("Enviroment file not exists.")
  63. exit(-1)
  64. if not rooms.is_file():
  65. print("Rooms index config not exists.")
  66. exit(-1)
  67. if not items.is_file():
  68. print("Items index config not exists.")
  69. exit(-1)
  70. if not textures.is_dir():
  71. print("Textures directory in config not exists.")
  72. exit(-1)
  73. if not objects.is_dir():
  74. print("Objects directory in config not exists.")
  75. exit(-1)
  76. # Checking that directories exists
  77. if not source.is_dir():
  78. print("Source directory not exists.")
  79. exit(-1)
  80. if not script_source.is_dir():
  81. print("Script source directory not exists.")
  82. exit(-1)
  83. if not sass_source.is_dir():
  84. print("Sass source director not exists.")
  85. exit(-1)
  86. if not static_files.is_dir():
  87. print("Static files directory not exists.")
  88. exit(-1)
  89. if not templates.is_dir():
  90. print("Templates directory not exists.")
  91. exit(-1)
  92. # Checking files
  93. if not app_view_file.is_file():
  94. print("App view file not exists.")
  95. exit(-1)
  96. # Check config file
  97. if not config.is_file():
  98. print("App config file not exists.")
  99. exit(-1)
  100. # Check script loader file
  101. if not script_loader_file.is_file():
  102. print("Script loader file not exists.")
  103. exit(-1)
  104. # Check SASS loader file
  105. if not sass_loader_file.is_file():
  106. print("SASS loader file not exists.")
  107. exit(-1)
  108. # Check that SASS loading screen file exists
  109. if not sass_loading_screen_file.is_file():
  110. print("SASS loading screen file not exists.")
  111. exit(-1)
  112. # Prepare result directory
  113. if build.is_dir():
  114. shutil.rmtree(build)
  115. build.mkdir()
  116. # Parse config json
  117. try:
  118. with config.open() as handle:
  119. config = json.loads(handle.read())
  120. except event:
  121. print(str(event))
  122. print("Can not parse config file.")
  123. exit(-1)
  124. def get_config_section(
  125. name: str,
  126. alt: str | int | float | list | None = None
  127. ) -> str | int | float | list:
  128. '''
  129. This get section from root config file, or raise exception when section
  130. not exists, and alt is set to None. When alt is provided, and section
  131. not exists then return alt. If section exists, then return section.
  132. Parameters:
  133. name (str): Name of the section
  134. alt (str | int | float | list | None) = None: Alternative value
  135. Returns:
  136. (str | int | flaot | list): Value of the section
  137. '''
  138. global config
  139. if name in config:
  140. return config[name]
  141. if alt is not None:
  142. return alt
  143. print("Not found section \"" + name + "\" in config.")
  144. exit(-2)
  145. def compile(*command: list) -> None:
  146. '''
  147. This function execute command, and when command not exit without
  148. error code, that mean not return 0, then it print STDOUT and STDERR
  149. from the command.
  150. Parameters:
  151. command (list): Command as list of str
  152. '''
  153. result = subprocess.run(command, capture_output = True)
  154. if result.returncode == 0:
  155. return
  156. print(result.stdout.decode("UTF-8"))
  157. print(result.stderr.decode("UTF-8"))
  158. print("Compilation end with error.")
  159. exit(-5)
  160. # Rendering app view
  161. from source.make.render import render
  162. from source.make.dom import link, script, style
  163. app_view_render = render(app_view_file)
  164. # App view use HTML description as replace tags
  165. app_view_render.start_tag = "{{"
  166. app_view_render.stop_tag = "}}"
  167. view_params = get_config_section("view-params")
  168. # Replace all elements from view-params config section
  169. for param in view_params.keys():
  170. content = view_params[param]
  171. if type(content) is str:
  172. app_view_render.add(param, content)
  173. continue
  174. if type(content) is float or type(content) is int:
  175. app_view_render.add(param, str(content))
  176. continue
  177. print("Param " + param + " not contain string or number.")
  178. exit(-3)
  179. # Compile loading screen sass file
  180. compile(
  181. "sass",
  182. "--sourcemap=none",
  183. "-t compressed",
  184. str(sass_loading_screen_file),
  185. str(sass_loading_screen_tmp_file)
  186. )
  187. # Open compiled tmp file, add it to view, and drop tmp file
  188. loading_screen = style()
  189. with sass_loading_screen_tmp_file.open() as handle:
  190. loading_screen.content = handle.read()
  191. sass_loading_screen_tmp_file.unlink()
  192. # Generating tags
  193. sass_link = link()
  194. sass_link.rel = "stylesheet"
  195. sass_link.type = "text/css"
  196. sass_link.href = "./" + sass_loader_result_file.name + "?version=" + release
  197. js_script = script()
  198. js_script.src = "./" + script_loader_result_file.name + "?version=" + release
  199. # Add Three.js
  200. three_js = script()
  201. three_js.src = "https://unpkg.com/[email protected]/build/three.min.js"
  202. bundle_items = (
  203. sass_link.render() +
  204. js_script.render() +
  205. three_js.render() +
  206. loading_screen.render()
  207. )
  208. # Add bundle items tags
  209. app_view_render.add("bundle_items", bundle_items)
  210. # Render and save app view
  211. app_view = app_view_render.finalize()
  212. try:
  213. with app_view_result_file.open("w") as handle:
  214. handle.write(app_view)
  215. except event:
  216. print("Can not save app view.")
  217. print(str(event))
  218. exit(-4)
  219. # Bundle JS script source
  220. compile(
  221. "esbuild",
  222. str(script_loader_file),
  223. "--bundle",
  224. "--outfile=" + str(script_loader_result_file)
  225. )
  226. # Bundle SASS themes source
  227. compile(
  228. "sass",
  229. "--sourcemap=none",
  230. "-t compressed",
  231. str(sass_loader_file),
  232. str(sass_loader_result_file)
  233. )
  234. # Copy static folder
  235. compile(
  236. "cp",
  237. "-r",
  238. str(static_files),
  239. str(static_files_output)
  240. )
  241. # Copy config folder
  242. compile(
  243. "cp",
  244. "-r",
  245. str(app_config),
  246. str(output_config)
  247. )
  248. print("Build success!")