""" Custom runserver command that automatically starts CSS watcher. Overrides Django's default runserver to include pnpm dev. """ import signal import subprocess import sys from django.conf import settings from django.contrib.staticfiles.management.commands.runserver import ( Command as RunserverCommand, ) class Command(RunserverCommand): help = "Run development server with automatic CSS building" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.css_process = None def handle(self, *args, **options): """Start CSS watcher before running Django dev server.""" self.stdout.write(self.style.SUCCESS("Starting CSS watcher (pnpm dev)...")) # Start pnpm dev in background try: self.css_process = subprocess.Popen( ["pnpm", "run", "dev"], cwd=settings.BASE_DIR, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, ) self.stdout.write(self.style.SUCCESS("✓ CSS watcher started\n")) except FileNotFoundError: self.stdout.write( self.style.WARNING( "Warning: pnpm not found. CSS will not be rebuilt automatically.\n" 'Install pnpm or run "pnpm run dev" manually in another terminal.\n' ) ) except Exception as e: self.stdout.write( self.style.WARNING(f"Warning: Could not start CSS watcher: {e}\n") ) # Register cleanup handler original_sigint = signal.getsignal(signal.SIGINT) original_sigterm = signal.getsignal(signal.SIGTERM) def cleanup(signum, frame): self.stdout.write("\nShutting down...") if self.css_process: self.css_process.terminate() try: self.css_process.wait(timeout=5) self.stdout.write(self.style.SUCCESS("✓ CSS watcher stopped")) except subprocess.TimeoutExpired: self.css_process.kill() # Call original handler if signum == signal.SIGINT and callable(original_sigint): original_sigint(signum, frame) elif signum == signal.SIGTERM and callable(original_sigterm): original_sigterm(signum, frame) sys.exit(0) signal.signal(signal.SIGINT, cleanup) signal.signal(signal.SIGTERM, cleanup) # Run Django dev server try: super().handle(*args, **options) finally: # Cleanup on normal exit if self.css_process: self.css_process.terminate() try: self.css_process.wait(timeout=5) except subprocess.TimeoutExpired: self.css_process.kill()