Add PyCharm Dev run config and dev runner script
- run_dev.py: starts proxy, admin and frontend together with colored output per process; handles SIGTERM from PyCharm Stop button - .idea/runConfigurations/Dev.xml: PyCharm Python run config - .gitignore: allow Dev.xml via layered negation pattern - vite.config.js: open browser automatically on dev server start
This commit is contained in:
parent
dd8f69ecb6
commit
cdaec894d8
5
.gitignore
vendored
5
.gitignore
vendored
@ -14,7 +14,10 @@ __pycache__/
|
||||
*.sqlite3
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.idea/*
|
||||
!.idea/runConfigurations/
|
||||
.idea/runConfigurations/*
|
||||
!.idea/runConfigurations/Dev.xml
|
||||
.vscode/
|
||||
|
||||
# Frontend build
|
||||
|
||||
16
.idea/runConfigurations/Dev.xml
generated
Normal file
16
.idea/runConfigurations/Dev.xml
generated
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Dev" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="llm_quota" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="false" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/run_dev.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
86
run_dev.py
Normal file
86
run_dev.py
Normal file
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Dev runner: startet Proxy, Admin-API und Frontend gemeinsam."""
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
import subprocess
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load_env(path: Path):
|
||||
if not path.exists():
|
||||
return
|
||||
for line in path.read_text(encoding='utf-8').splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#') and '=' in line:
|
||||
key, _, val = line.partition('=')
|
||||
os.environ.setdefault(key.strip(), val.strip().strip('"\''))
|
||||
|
||||
|
||||
def pipe_output(proc: subprocess.Popen, label: str, color: str):
|
||||
reset = '\033[0m'
|
||||
prefix = f'\033[{color}m[{label}]{reset} '
|
||||
for raw in iter(proc.stdout.readline, b''):
|
||||
sys.stdout.write(prefix + raw.decode(errors='replace'))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def main():
|
||||
root = Path(__file__).parent
|
||||
load_env(root / '.env')
|
||||
|
||||
if not os.environ.get('ADMIN_PASSWORD'):
|
||||
print('Fehler: ADMIN_PASSWORD nicht gesetzt (siehe .env)')
|
||||
sys.exit(1)
|
||||
|
||||
python = root / '.venv' / 'bin' / 'python'
|
||||
backend = root / 'backend'
|
||||
frontend = root / 'frontend'
|
||||
|
||||
proxy_host = os.environ.get('PROXY_HOST', '0.0.0.0')
|
||||
proxy_port = os.environ.get('PROXY_PORT', '8000')
|
||||
admin_port = os.environ.get('ADMIN_PORT', '8001')
|
||||
|
||||
print('Initialisiere Datenbank...')
|
||||
subprocess.run([str(python), 'init_db.py'], cwd=backend, check=True)
|
||||
|
||||
print(f'Starte Proxy → http://{proxy_host}:{proxy_port}')
|
||||
print(f'Starte Admin-API → http://127.0.0.1:{admin_port}')
|
||||
print('Starte Frontend → http://localhost:5173')
|
||||
|
||||
env = {**os.environ, 'PYTHONUNBUFFERED': '1'}
|
||||
|
||||
procs = [
|
||||
(subprocess.Popen(
|
||||
[str(python), '-m', 'uvicorn', 'main:app', '--reload',
|
||||
'--host', proxy_host, '--port', proxy_port],
|
||||
cwd=backend, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
|
||||
), 'Proxy ', '34'), # blau
|
||||
(subprocess.Popen(
|
||||
[str(python), '-m', 'uvicorn', 'admin:app', '--reload',
|
||||
'--host', '127.0.0.1', '--port', admin_port],
|
||||
cwd=backend, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
|
||||
), 'Admin ', '33'), # gelb
|
||||
(subprocess.Popen(
|
||||
['npm', 'run', 'dev'],
|
||||
cwd=frontend, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
), 'Frontend', '32'), # grün
|
||||
]
|
||||
|
||||
for proc, label, color in procs:
|
||||
threading.Thread(target=pipe_output, args=(proc, label, color), daemon=True).start()
|
||||
|
||||
def stop(*_):
|
||||
for p, _, _ in procs:
|
||||
p.terminate()
|
||||
|
||||
signal.signal(signal.SIGINT, stop)
|
||||
signal.signal(signal.SIGTERM, stop)
|
||||
|
||||
for p, _, _ in procs:
|
||||
p.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
x
Reference in New Issue
Block a user