282 lines
8.4 KiB
Python
Raw Permalink Normal View History

2025-05-29 23:50:41 +08:00
#!/usr/bin/env python3
"""
Development environment management script for the Crypto Trading Bot Dashboard.
"""
import subprocess
import sys
import time
import os
from pathlib import Path
def run_command(command: str, check: bool = True) -> subprocess.CompletedProcess:
"""Run a shell command and return the result."""
print(f"Running: {command}")
return subprocess.run(command, shell=True, check=check)
def check_docker():
"""Check if Docker is installed and running."""
try:
result = subprocess.run(
"docker --version", shell=True, capture_output=True, text=True
)
if result.returncode != 0:
print("❌ Docker is not installed or not in PATH")
return False
result = subprocess.run(
"docker info", shell=True, capture_output=True, text=True
)
if result.returncode != 0:
print("❌ Docker daemon is not running")
return False
print("✅ Docker is available and running")
return True
except Exception as e:
print(f"❌ Error checking Docker: {e}")
return False
def start_services():
"""Start all development services."""
print("🚀 Starting development environment...")
if not check_docker():
sys.exit(1)
# Start Docker services
run_command("docker-compose up -d")
# Wait for services to be ready
print("⏳ Waiting for services to be ready...")
time.sleep(10)
# Check service health
check_services()
def stop_services():
"""Stop all development services."""
print("🛑 Stopping development environment...")
run_command("docker-compose down")
def restart_services():
"""Restart all development services."""
print("🔄 Restarting development environment...")
stop_services()
start_services()
def check_services():
"""Check the status of all services."""
print("🔍 Checking service status...")
# Check Docker containers
result = subprocess.run(
"docker-compose ps", shell=True, capture_output=True, text=True
)
print(result.stdout)
# Check database connection
check_database()
def check_database():
"""Check if the database is accessible."""
try:
import psycopg2
from dotenv import load_dotenv
# Load environment variables
env_file = Path(".env")
if env_file.exists():
load_dotenv(env_file)
conn_params = {
"host": os.getenv("POSTGRES_HOST", "localhost"),
"port": os.getenv("POSTGRES_PORT", "5434"),
2025-05-29 23:50:41 +08:00
"database": os.getenv("POSTGRES_DB", "dashboard"),
"user": os.getenv("POSTGRES_USER", "dashboard"),
"password": os.getenv("POSTGRES_PASSWORD"),
2025-05-29 23:50:41 +08:00
}
conn = psycopg2.connect(**conn_params)
conn.close()
print("✅ Database connection successful")
except ImportError:
print("⚠️ psycopg2 not installed, skipping database check")
except Exception as e:
print(f"❌ Database connection failed: {e}")
def setup_env():
"""Set up environment files."""
print("📝 Setting up environment...")
env_file = Path(".env")
template_file = Path("env.template")
if not env_file.exists() and template_file.exists():
import shutil
shutil.copy(template_file, env_file)
print(f"✅ Created .env file from template")
print(f"⚠️ Please update .env with your actual configuration")
elif env_file.exists():
print("✅ .env file already exists")
else:
print("❌ No env.template file found")
def install_deps():
"""Install project dependencies using UV."""
print("📦 Installing dependencies...")
run_command("uv sync --dev")
def run_dev_server():
"""Run the development server with hot reload."""
print("🔥 Starting development server with hot reload...")
try:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import threading
import signal
class ChangeHandler(FileSystemEventHandler):
def __init__(self, restart_callback):
self.restart_callback = restart_callback
self.last_modified = 0
def on_modified(self, event):
if event.is_directory:
return
# Only watch Python files
if not event.src_path.endswith('.py'):
return
# Avoid rapid restarts
current_time = time.time()
if current_time - self.last_modified < 1:
return
self.last_modified = current_time
print(f"\n📝 File changed: {event.src_path}")
self.restart_callback()
# Application process
app_process = None
def start_app():
nonlocal app_process
if app_process:
app_process.terminate()
app_process.wait()
print("🚀 Starting application...")
app_process = subprocess.Popen([
sys.executable, "main.py"
])
def restart_app():
print("🔄 Restarting application...")
start_app()
# Set up file watcher
event_handler = ChangeHandler(restart_app)
observer = Observer()
# Watch main directories
watch_dirs = [".", "config", "database", "components", "data", "strategies", "trader"]
for watch_dir in watch_dirs:
if Path(watch_dir).exists():
observer.schedule(event_handler, watch_dir, recursive=True)
print(f"👀 Watching: {watch_dir}/")
# Start watching
observer.start()
# Start initial app
start_app()
def signal_handler(signum, frame):
print("\n🛑 Shutting down development server...")
observer.stop()
if app_process:
app_process.terminate()
app_process.wait()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print("🔥 Development server running with hot reload")
print("📁 Watching for changes in Python files...")
print("Press Ctrl+C to stop")
# Keep the main thread alive
observer.join()
except ImportError:
print("❌ watchdog not installed, running without hot reload")
print("Install with: uv add watchdog")
# Fallback to regular execution
run_command("uv run python main.py")
except KeyboardInterrupt:
print("\n🛑 Development server stopped")
except Exception as e:
print(f"❌ Error running dev server: {e}")
def run_app():
"""Run the application without hot reload."""
print("🚀 Starting application...")
run_command("uv run python main.py")
def main():
"""Main entry point for the development script."""
if len(sys.argv) < 2:
print("Usage: python scripts/dev.py [command]")
print("Commands:")
print(" setup - Set up environment and install dependencies")
print(" start - Start development services (Docker)")
print(" stop - Stop development services")
print(" restart - Restart development services")
print(" status - Check service status")
print(" install - Install dependencies")
print(" dev-server - Run development server with hot reload")
print(" run - Run application without hot reload")
sys.exit(1)
command = sys.argv[1]
if command == "setup":
setup_env()
install_deps()
elif command == "start":
start_services()
elif command == "stop":
stop_services()
elif command == "restart":
restart_services()
elif command == "status":
check_services()
elif command == "install":
install_deps()
elif command == "dev-server":
run_dev_server()
elif command == "run":
run_app()
else:
print(f"Unknown command: {command}")
sys.exit(1)
if __name__ == "__main__":
main()