#!/usr/bin/python ### ### Build script for the la-warch app. This script is responsible ### for building app from source, and config. Config file is ### ### ./config.json ### ### This file has documentation, with options that could be change to ### make this app more flexible for the end users. if not __name__ == "__main__": print("This is build system. Can be only executed as app.") exit(-2) import json import pathlib import shutil import subprocess import datetime # Current release release = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") # Root project directory root = pathlib.Path("./") # This is root source dir source = root / pathlib.Path("./source/") # Sources with types of content script_source = source / pathlib.Path("./scripts/") sass_source = source / pathlib.Path("./theme/") static_files = source / pathlib.Path("./static/") templates = source / pathlib.Path("./templates/") # Specific files, like loaders, main view, etc. app_view_file = templates / pathlib.Path("view.html") script_loader_file = script_source / pathlib.Path("loader.js") sass_loader_file = sass_source / pathlib.Path("loader.sass") sass_loading_screen_file = sass_source / pathlib.Path("loading-screen.sass") config = root / pathlib.Path("config.json") # Build dir build = root / pathlib.Path("./build/") # Result specific files app_view_result_file = build / pathlib.Path("index.html") script_loader_result_file = build / pathlib.Path("bundle.js") sass_loader_result_file = build / pathlib.Path("bundle.css") sass_loading_screen_tmp_file = build / pathlib.Path("loading-screen.css") static_files_output = build / pathlib.Path("static") output_config = static_files_output / pathlib.Path("config") # App config directory app_config = root / pathlib.Path("config/") app_example_config = root / pathlib.Path("example_config/") # Check app config if not app_config.is_dir(): app_config = app_example_config print("Custom config not found. Using example config.") if not app_config.is_dir(): print("App example config not exists.") exit(-1) # App config files and directories enviroment = app_config / pathlib.Path("enviroment.json") rooms = app_config / pathlib.Path("rooms.json") items = app_config / pathlib.Path("items.json") textures = app_config / pathlib.Path("textures") objects = app_config / pathlib.Path("objects") # Checking config directories if not enviroment.is_file(): print("Enviroment file not exists.") exit(-1) if not rooms.is_file(): print("Rooms index config not exists.") exit(-1) if not items.is_file(): print("Items index config not exists.") exit(-1) if not textures.is_dir(): print("Textures directory in config not exists.") exit(-1) if not objects.is_dir(): print("Objects directory in config not exists.") exit(-1) # Checking that directories exists if not source.is_dir(): print("Source directory not exists.") exit(-1) if not script_source.is_dir(): print("Script source directory not exists.") exit(-1) if not sass_source.is_dir(): print("Sass source director not exists.") exit(-1) if not static_files.is_dir(): print("Static files directory not exists.") exit(-1) if not templates.is_dir(): print("Templates directory not exists.") exit(-1) # Checking files if not app_view_file.is_file(): print("App view file not exists.") exit(-1) # Check config file if not config.is_file(): print("App config file not exists.") exit(-1) # Check script loader file if not script_loader_file.is_file(): print("Script loader file not exists.") exit(-1) # Check SASS loader file if not sass_loader_file.is_file(): print("SASS loader file not exists.") exit(-1) # Check that SASS loading screen file exists if not sass_loading_screen_file.is_file(): print("SASS loading screen file not exists.") exit(-1) # Prepare result directory if build.is_dir(): shutil.rmtree(build) build.mkdir() # Parse config json try: with config.open() as handle: config = json.loads(handle.read()) except event: print(str(event)) print("Can not parse config file.") exit(-1) def get_config_section( name: str, alt: str | int | float | list | None = None ) -> str | int | float | list: ''' This get section from root config file, or raise exception when section not exists, and alt is set to None. When alt is provided, and section not exists then return alt. If section exists, then return section. Parameters: name (str): Name of the section alt (str | int | float | list | None) = None: Alternative value Returns: (str | int | flaot | list): Value of the section ''' global config if name in config: return config[name] if alt is not None: return alt print("Not found section \"" + name + "\" in config.") exit(-2) def compile(*command: list) -> None: ''' This function execute command, and when command not exit without error code, that mean not return 0, then it print STDOUT and STDERR from the command. Parameters: command (list): Command as list of str ''' result = subprocess.run(command, capture_output = True) if result.returncode == 0: return print(result.stdout.decode("UTF-8")) print(result.stderr.decode("UTF-8")) print("Compilation end with error.") exit(-5) # Rendering app view from source.make.render import render from source.make.dom import link, script, style app_view_render = render(app_view_file) # App view use HTML description as replace tags app_view_render.start_tag = "{{" app_view_render.stop_tag = "}}" view_params = get_config_section("view-params") # Replace all elements from view-params config section for param in view_params.keys(): content = view_params[param] if type(content) is str: app_view_render.add(param, content) continue if type(content) is float or type(content) is int: app_view_render.add(param, str(content)) continue print("Param " + param + " not contain string or number.") exit(-3) # Compile loading screen sass file compile( "sass", "--sourcemap=none", "-t compressed", str(sass_loading_screen_file), str(sass_loading_screen_tmp_file) ) # Open compiled tmp file, add it to view, and drop tmp file loading_screen = style() with sass_loading_screen_tmp_file.open() as handle: loading_screen.content = handle.read() sass_loading_screen_tmp_file.unlink() # Generating tags sass_link = link() sass_link.rel = "stylesheet" sass_link.type = "text/css" sass_link.href = "./" + sass_loader_result_file.name + "?version=" + release js_script = script() js_script.src = "./" + script_loader_result_file.name + "?version=" + release # Add Three.js three_js = script() three_js.src = "https://unpkg.com/three@0.149.0/build/three.min.js" bundle_items = ( sass_link.render() + js_script.render() + three_js.render() + loading_screen.render() ) # Add bundle items tags app_view_render.add("bundle_items", bundle_items) # Render and save app view app_view = app_view_render.finalize() try: with app_view_result_file.open("w") as handle: handle.write(app_view) except event: print("Can not save app view.") print(str(event)) exit(-4) # Bundle JS script source compile( "esbuild", str(script_loader_file), "--bundle", "--outfile=" + str(script_loader_result_file) ) # Bundle SASS themes source compile( "sass", "--sourcemap=none", "-t compressed", str(sass_loader_file), str(sass_loader_result_file) ) # Copy static folder compile( "cp", "-r", str(static_files), str(static_files_output) ) # Copy config folder compile( "cp", "-r", str(app_config), str(output_config) ) print("Build success!")