File size: 3,688 Bytes
75123b0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""Own all development child processes, including npm and uvicorn descendants."""

import argparse
import os
import signal
import subprocess
import sys
import time
import urllib.request
import webbrowser
from pathlib import Path

root = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser()
parser.add_argument("--port", type=int, default=8010)
parser.add_argument("--no-open", action="store_true")
args = parser.parse_args()
url = f"http://127.0.0.1:{args.port}"
stop = False


def request_stop(*_):
    global stop
    stop = True


signal.signal(signal.SIGINT, request_stop)
signal.signal(signal.SIGTERM, request_stop)
processes = []
logs = []
try:
    for cmd, cwd, logname in [
        (["npm", "run", "watch"], root / "frontend", "frontend.log"),
        (
            [
                sys.executable,
                "-m",
                "uvicorn",
                "app.main:app",
                "--app-dir",
                "backend",
                "--host",
                "127.0.0.1",
                "--port",
                str(args.port),
                "--reload",
                "--reload-dir",
                "backend/app",
            ],
            root,
            "backend.log",
        ),
    ]:
        log = (root / ".runtime" / logname).open("w")
        logs.append(log)
        processes.append(
            subprocess.Popen(
                cmd,
                cwd=cwd,
                stdout=log,
                stderr=subprocess.STDOUT,
                start_new_session=True,
            )
        )
    ready = False
    for _ in range(60):
        if stop:
            break
        if any(p.poll() is not None for p in processes):
            raise RuntimeError(
                "Um processo encerrou. Consulte .runtime/backend.log e frontend.log."
            )
        try:
            with urllib.request.urlopen(url + "/api/health", timeout=1) as r:
                ready = r.status == 200
        except Exception:
            pass
        if ready:
            break
        time.sleep(1)
    if not ready and not stop:
        raise RuntimeError(
            "A aplicação não respondeu em 60 segundos. Consulte .runtime/backend.log."
        )
    if ready:
        from dotenv import dotenv_values

        settings = dotenv_values(root / ".env")
        identity = (
            "Login: mesmos usuários e senhas da MESA (matrícula sem dígito)."
            if os.getenv("AUTH_PROVIDER", settings.get("AUTH_PROVIDER", "mesa"))
            == "mesa"
            else f'Acesso inicial: {root / ".runtime/dev-access.txt"}'
        )
        print(
            f"\nCARLA em desenvolvimento: {url}\nPorta de entrada: carla\n{identity}\nFrontend: recompila ao salvar; atualize a página para ver as mudanças.\nBackend: recarrega automaticamente. Logs em .runtime/.\nCtrl+C encerra todos os processos.\n",
            flush=True,
        )
        if not args.no_open:
            webbrowser.open(url)
    while not stop:
        if any(p.poll() is not None for p in processes):
            raise RuntimeError("Um processo encerrou; consulte os logs em .runtime/.")
        time.sleep(0.5)
except Exception as exc:
    print(str(exc), file=sys.stderr)
    sys.exit(1)
finally:
    for process in processes:
        try:
            os.killpg(process.pid, signal.SIGTERM)
        except ProcessLookupError:
            pass
    for process in processes:
        try:
            process.wait(timeout=7)
        except subprocess.TimeoutExpired:
            try:
                os.killpg(process.pid, signal.SIGKILL)
            except ProcessLookupError:
                pass
    for log in logs:
        log.close()