myhomelab/src/bootstrap.py
neo.webmaster.2@gmail.com 7e0d9b68be
Some checks are pending
Python Code Quality / lock_file (push) Waiting to run
Python Code Quality / linting (push) Blocked by required conditions
Python Code Quality / formatting (push) Blocked by required conditions
Python Code Quality / type_consistency (push) Blocked by required conditions
Python Code Quality / tests (push) Blocked by required conditions
Python Code Quality / build (push) Blocked by required conditions
"Auto-commit via make git"
2026-03-05 08:11:11 +01:00

135 lines
4.3 KiB
Python

from __future__ import annotations
from pathlib import Path
import os
import shutil
import subprocess
import sys
class Application:
def __init__(self, *args, **kwargs):
for key in kwargs:
setattr(self, key, kwargs[key])
self.base_path = Path(__file__).resolve().parents[1]
self.venv_path = self.base_path / ".venv" # uv default
self._hello()
# -------- UX --------
def _hello(self):
print(f"🚀 Iniciando o {getattr(self, 'package', '')} {getattr(self, 'version', '')}...")
def _print(self, msg: str):
print(f"[{getattr(self, 'package', '')}] {msg}", flush=True)
# -------- main --------
def run(self):
os.chdir(self.base_path)
uv = self.ensure_uv()
self.ensure_venv(uv)
self.ensure_dependencies(uv)
self.launch_neuro(uv)
# -------- uv / env --------
def ensure_uv(self) -> str:
"""
Garante que o comando `uv` existe no host.
Estratégia:
1) PATH
2) `python -m uv` (se uv estiver instalado no python do host)
3) fallback: instala uv via pip (host python) e tenta de novo
"""
if shutil.which("uv"):
self._print("uv encontrado no PATH.")
return "uv"
# tenta via `python -m uv` (muitas vezes funciona em ambientes dev)
try:
subprocess.run([sys.executable, "-m", "uv", "--version"], check=True, capture_output=True, text=True)
self._print("uv disponível via `python -m uv`.")
return f"{sys.executable} -m uv"
except Exception:
pass
# fallback pragmatico: pip install uv (host python)
self._print("uv não encontrado. Tentando instalar via pip no Python do host...")
try:
subprocess.run([sys.executable, "-m", "pip", "install", "--user", "uv"], check=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(
"Não consegui instalar o `uv`. Instala manualmente e tenta novamente.\n"
"Sugestões:\n"
" - pip install --user uv\n"
" - ou usa o instalador oficial do uv\n"
) from e
if shutil.which("uv"):
self._print("uv instalado e disponível no PATH.")
return "uv"
# última tentativa: python -m uv
subprocess.run([sys.executable, "-m", "uv", "--version"], check=True)
self._print("uv instalado e disponível via `python -m uv`.")
return f"{sys.executable} -m uv"
def _uv(self, uv_cmd: str, *args: str) -> None:
"""
Executa um comando uv, aceitando uv_cmd como:
- "uv"
- "<python> -m uv"
"""
cmd = uv_cmd.split() + list(args)
self._print(" ".join(cmd))
subprocess.run(cmd, check=True)
def ensure_venv(self, uv_cmd: str) -> None:
"""
Garante que existe um venv gerido pelo uv em .venv.
"""
if self.venv_path.exists():
self._print("Ambiente .venv já existente.")
return
self._print("Criando ambiente .venv via uv...")
# uv cria .venv por default; este comando respeita pyproject
self._uv(uv_cmd, "venv")
def ensure_dependencies(self, uv_cmd: str) -> None:
"""
Instala/sincroniza deps. Com uv.lock presente, o correto é uv sync.
"""
lock = self.base_path / "uv.lock"
pyproject = self.base_path / "pyproject.toml"
if not pyproject.exists():
raise RuntimeError("pyproject.toml não encontrado na raiz do projeto.")
if lock.exists():
self._print("Sincronizando dependências via uv.lock (uv sync)...")
self._uv(uv_cmd, "sync")
else:
# Se ainda não há lock, tenta resolver e criar
self._print("uv.lock não encontrado. Resolvendo dependências (uv lock + uv sync)...")
self._uv(uv_cmd, "lock")
self._uv(uv_cmd, "sync")
# -------- launch --------
def launch_neuro(self, uv_cmd: str) -> None:
"""
Entry point: roda a app dentro do ambiente uv.
Preferência: módulo -m neuro (usa src layout corretamente).
"""
# Se tens __main__.py em neuro, isto é perfeito:
self._print("Iniciando neuro via uv run...")
self._uv(uv_cmd, "run", "python", "-m", "neuro")