build_frontend.py
1 import os 2 import shutil 3 import subprocess 4 from sys import exit as sys_exit 5 from sys import stdout 6 7 from hatchling.builders.hooks.plugin.interface import BuildHookInterface 8 9 10 class CustomBuildHook(BuildHookInterface): 11 def initialize(self, version, build_data): 12 super().initialize(version, build_data) 13 14 # Check if we should skip UI builds (static assets already present) 15 skip_ui_build = os.environ.get("SAM_SKIP_UI_BUILD", "").lower() in ( 16 "true", 17 "1", 18 "yes", 19 ) 20 21 if skip_ui_build: 22 self.app.display_info("SAM_SKIP_UI_BUILD is set, skipping UI build steps\n") 23 self.app.display_info("Verifying static assets exist...\n") 24 25 required_paths = [ 26 "config_portal/frontend/static", 27 "client/webui/frontend/static", 28 "docs/build", 29 ] 30 31 missing = [p for p in required_paths if not os.path.exists(p)] 32 if missing: 33 raise RuntimeError( 34 f"SAM_SKIP_UI_BUILD is set but required static assets are missing: {', '.join(missing)}" 35 ) 36 37 self.app.display_info( 38 "All required static assets found, proceeding with Python build only\n" 39 ) 40 return 41 42 npm = shutil.which("npm") 43 if npm is None: 44 raise RuntimeError( 45 "NodeJS `npm` is required for building Solace Agent Mesh but it was not found" 46 ) 47 build_log_file = "build.log" 48 log_file = open(build_log_file, "w", encoding="utf-8") 49 50 def log(message): 51 stdout.write(message) 52 log_file.write(message) 53 54 def build_failed(message): 55 log(f"\nError during build: {message}\n") 56 log( 57 f"Build failed. Please check the logs for details at {os.path.abspath(log_file.name)}\n" 58 ) 59 if log_file: 60 log_file.close() 61 sys_exit(1) 62 63 log(f"Build logs will be written to {os.path.abspath(log_file.name)}\n") 64 log(">>> Building Solace Agent Mesh Config Portal\n") 65 os.chdir("config_portal/frontend") 66 try: 67 log("### npm ci") 68 subprocess.run( 69 [npm, "ci"], check=True, stdout=log_file, stderr=subprocess.STDOUT 70 ) 71 log("\n### npm run build\n") 72 subprocess.run( 73 [npm, "run", "build"], 74 check=True, 75 stdout=log_file, 76 stderr=subprocess.STDOUT, 77 ) 78 except subprocess.CalledProcessError: 79 build_failed("Config Portal build failed with error") 80 finally: 81 os.chdir("../..") 82 83 log(">>> Building Solace Agent Mesh Web UI\n") 84 os.chdir("client/webui/frontend") 85 try: 86 log("### npm ci") 87 subprocess.run( 88 [npm, "ci"], check=True, stdout=log_file, stderr=subprocess.STDOUT 89 ) 90 log("\n### npm run build\n") 91 subprocess.run( 92 [npm, "run", "build"], 93 check=True, 94 stdout=log_file, 95 stderr=subprocess.STDOUT, 96 ) 97 except subprocess.CalledProcessError: 98 build_failed( 99 "Web UI build failed with error", 100 ) 101 finally: 102 os.chdir("../../..") 103 104 log(">>> Building Solace Agent Mesh Documentation\n") 105 os.chdir("docs") 106 try: 107 log("### npm ci") 108 subprocess.run( 109 [npm, "ci"], check=True, stdout=log_file, stderr=subprocess.STDOUT 110 ) 111 log("\n### npm run build\n") 112 subprocess.run( 113 [npm, "run", "build"], 114 check=True, 115 stdout=log_file, 116 stderr=subprocess.STDOUT, 117 ) 118 except subprocess.CalledProcessError: 119 build_failed("Documentation build failed with error") 120 finally: 121 os.chdir("..") 122 123 log(">>> Build completed successfully\n") 124 log_file.close()