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
135 lines
4.3 KiB
Python
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")
|
|
|
|
|
|
|