| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- """
- dev.py
- ======
- This script acts as a local development orchestrator. Instead of recreating the frontend
- in Python, which would violate the "Don't Repeat Yourself" (DRY) principle and introduce
- massive technical debt, this script leverages the existing architecture.
- It performs four main actions sequentially:
- 1. Executes `roi.py` to fetch the latest market data and generate the frontend JSON files.
- 2. Executes `bun install` to ensure frontend JS dependencies are present.
- 3. Executes `bun run build` to compile the TypeScript frontend into browser-ready JavaScript.
- 4. Spawns a local Python HTTP server pointing to the `www/` directory.
- """
- import os # Required for changing working directories and checking paths.
- import subprocess # Required for spawning external processes (like 'bun' and other python scripts).
- import sys # Required to grab the current Python executable path.
- import http.server # Required to run the local web server.
- import socketserver # Required to bind the HTTP handler to a specific port.
- def main() -> None:
- """
- Main execution function for the local development server orchestrator.
- """
- # -------------------------------------------------------------------------
- # STEP 1: GENERATE BACKEND DATA
- # -------------------------------------------------------------------------
- print(">>> [1/4] Running roi.py to generate updated JSON data...")
- try:
- subprocess.run([sys.executable, "roi.py"], check=True)
- except subprocess.CalledProcessError as e:
- sys.exit(f"!!! Error: Failed to execute roi.py. Process exited with code {e.returncode}")
- # -------------------------------------------------------------------------
- # STEP 2: INSTALL FRONTEND DEPENDENCIES
- # -------------------------------------------------------------------------
- print(">>> [2/4] Installing frontend dependencies via Bun...")
-
- # EXTREME DETAIL: We create a copy of the current OS environment variables.
- # We then inject 'CI' = '1'. CI stands for Continuous Integration.
- # Most modern JS tools (like Bun, NPM, Yarn) look for this variable. If they see it,
- # they disable interactive terminal animations (like progress bars and emojis).
- # This prevents the child process from messing with the terminal driver and throwing
- # phantom SIGINT signals (KeyboardInterrupts) back to our Python script.
- env = os.environ.copy()
- env["CI"] = "1"
- try:
- # EXTREME DETAIL: stdin=subprocess.DEVNULL explicitly cuts the child process off
- # from reading keyboard input, further preventing terminal driver deadlocks.
- subprocess.run(["bun", "install"], check=True, env=env, stdin=subprocess.DEVNULL)
- except FileNotFoundError:
- sys.exit("!!! Error: 'bun' command not found. Please ensure Bun is installed (https://bun.sh/) and in your PATH.")
- except subprocess.CalledProcessError as e:
- sys.exit(f"!!! Error: Frontend dependency installation failed. Bun exited with code {e.returncode}")
- # -------------------------------------------------------------------------
- # STEP 3: BUILD THE FRONTEND
- # -------------------------------------------------------------------------
- print(">>> [3/4] Building the TypeScript frontend using Bun...")
- try:
- # We apply the same environment and stdin constraints to the build step for safety.
- subprocess.run(["bun", "run", "build"], check=True, env=env, stdin=subprocess.DEVNULL)
- except subprocess.CalledProcessError as e:
- sys.exit(f"!!! Error: Frontend build failed. Bun exited with code {e.returncode}")
- # -------------------------------------------------------------------------
- # STEP 4: SERVE THE FRONTEND LOCALLY
- # -------------------------------------------------------------------------
- print(">>> [4/4] Starting local development server...")
-
- PORT = 8000
- WEB_DIR = "www"
- if not os.path.isdir(WEB_DIR):
- sys.exit(f"!!! Error: Directory '{WEB_DIR}' does not exist. The build step may have failed silently.")
- os.chdir(WEB_DIR)
- Handler = http.server.SimpleHTTPRequestHandler
- with socketserver.TCPServer(("", PORT), Handler) as httpd:
- print(f">>> Serving at http://localhost:{PORT}")
- print(">>> Press Ctrl+C to stop the server.")
- httpd.serve_forever()
- if __name__ == '__main__':
- try:
- main()
- except KeyboardInterrupt:
- sys.exit("\n>>> Process interrupted by user. Exiting gracefully. Goodbye!")
|