Coverage for src/jtech_installer/cli/main_new.py: 0%

187 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-08-20 15:10 -0300

1#!/usr/bin/env python3 

2""" 

3🚀 JTECH™ Core Installer - CLI Principal 

4Instalador automatizado para configurar ambiente JTECH™ Core 

5""" 

6 

7import sys 

8import time 

9from pathlib import Path 

10 

11import click 

12from rich.console import Console 

13from rich.panel import Panel 

14from rich.progress import Progress, SpinnerColumn, TextColumn 

15from rich.table import Table 

16 

17from ..core.engine import InstallationEngine 

18from ..core.models import InstallationConfig, InstallationType, TeamType 

19from ..validator.integrity import IntegrityValidator 

20from ..validator.post_installation import PostInstallationValidator 

21 

22console = Console() 

23 

24 

25@click.group(invoke_without_command=True) 

26@click.option("--help", "-h", is_flag=True, help="Mostrar ajuda") 

27@click.option("--version", "-v", is_flag=True, help="Mostrar versão") 

28@click.option( 

29 "--team", 

30 "-t", 

31 type=click.Choice(["ide-minimal", "fullstack", "no-ui", "all"]), 

32 default="fullstack", 

33 help="Tipo de equipe/configuração", 

34) 

35@click.option("--force", "-f", is_flag=True, help="Forçar reinstalação") 

36@click.option( 

37 "--validate-only", is_flag=True, help="Apenas validar instalação existente" 

38) 

39@click.pass_context 

40def cli(ctx, help, version, team, force, validate_only): 

41 """ 

42 🚀 JTECH™ Core Installer 

43 

44 Instala e configura automaticamente o ambiente JTECH™ Core 

45 no projeto atual. 

46 

47 Exemplos: 

48 jtech-installer # Instala com configuração fullstack 

49 jtech-installer --team ide-minimal # Instala configuração mínima 

50 jtech-installer --validate-only # Apenas valida instalação 

51 jtech-installer --help # Mostra esta ajuda 

52 """ 

53 

54 if version: 

55 console.print("🚀 JTECH™ Core Installer v0.1.0", style="bold blue") 

56 return 

57 

58 if help or ctx.invoked_subcommand is not None: 

59 if help: 

60 console.print(ctx.get_help()) 

61 return 

62 

63 # Comando principal - instalar 

64 project_path = Path.cwd() 

65 

66 console.print( 

67 Panel.fit( 

68 f"[bold blue]🚀 JTECH™ Core Installer[/bold blue]\n" 

69 f"📁 Projeto: [cyan]{project_path}[/cyan]\n" 

70 f"⚙️ Tipo de equipe: [green]{team}[/green]", 

71 title="🔧 Configuração", 

72 border_style="blue", 

73 ) 

74 ) 

75 

76 if validate_only: 

77 return validate_installation(project_path, team) 

78 

79 return install_jtech_core(project_path, team, force) 

80 

81 

82def install_jtech_core( 

83 project_path: Path, team_type: str, force: bool = False 

84): 

85 """Executa a instalação completa do JTECH™ Core.""" 

86 

87 # Verificar se já existe instalação 

88 jtech_core = project_path / ".jtech-core" 

89 if jtech_core.exists() and not force: 

90 console.print("⚠️ Instalação JTECH™ Core já existe!", style="yellow") 

91 console.print("💡 Use --force para reinstalar", style="dim") 

92 

93 if not click.confirm("Deseja continuar e atualizar a instalação?"): 

94 console.print("❌ Instalação cancelada", style="red") 

95 return False 

96 

97 # Mapear tipo de equipe 

98 team_mapping = { 

99 "ide-minimal": TeamType.IDE_MINIMAL, 

100 "fullstack": TeamType.FULLSTACK, 

101 "no-ui": TeamType.NO_UI, 

102 "all": TeamType.ALL, 

103 } 

104 

105 team_enum = team_mapping[team_type] 

106 

107 # Determinar tipo de instalação 

108 install_type = ( 

109 InstallationType.BROWNFIELD 

110 if any( 

111 p.exists() 

112 for p in [ 

113 project_path / "package.json", 

114 project_path / "requirements.txt", 

115 project_path / "pom.xml", 

116 project_path / "Cargo.toml", 

117 ] 

118 ) 

119 else InstallationType.GREENFIELD 

120 ) 

121 

122 # Criar configuração 

123 config = InstallationConfig( 

124 project_path=project_path, 

125 install_type=install_type, 

126 team_type=team_enum, 

127 vs_code_integration=True, 

128 custom_config={}, 

129 framework_source_path=get_framework_source_path(), 

130 ) 

131 

132 # Executar instalação com progress 

133 with Progress( 

134 SpinnerColumn(), 

135 TextColumn("[progress.description]{task.description}"), 

136 console=console, 

137 ) as progress: 

138 

139 # Passo 1: Criar estrutura 

140 task = progress.add_task( 

141 "🏗️ Criando estrutura de diretórios...", total=None 

142 ) 

143 engine = InstallationEngine() 

144 

145 try: 

146 # Instalar 

147 result = engine.install(config) 

148 progress.update(task, description="✅ Estrutura criada") 

149 time.sleep(0.5) 

150 

151 # Passo 2: Copiar estrutura .jtech-core completa 

152 progress.update(task, description="📦 Copiando framework...") 

153 copy_jtech_core_structure(project_path) 

154 time.sleep(0.5) 

155 

156 # Passo 3: Copiar chatmodes 

157 progress.update(task, description="💬 Configurando chatmodes...") 

158 copy_chatmodes(project_path) 

159 time.sleep(0.5) 

160 

161 # Passo 4: Configurar VS Code 

162 progress.update(task, description="🔧 Configurando VS Code...") 

163 copy_vscode_config(project_path) 

164 time.sleep(0.5) 

165 

166 # Passo 5: Validar 

167 progress.update(task, description="🔍 Validando instalação...") 

168 validator = PostInstallationValidator(config) 

169 report = validator.validate_all() 

170 

171 progress.remove_task(task) 

172 

173 except Exception as e: 

174 progress.remove_task(task) 

175 console.print(f"❌ Erro durante instalação: {e}", style="red") 

176 return False 

177 

178 # Mostrar resultado 

179 show_installation_result(report, project_path) 

180 return True 

181 

182 

183def copy_jtech_core_structure(project_path: Path): 

184 """Copia toda a estrutura .jtech-core dos assets empacotados.""" 

185 assets_dir = Path(__file__).parent.parent / "assets" 

186 source_jtech = assets_dir / ".jtech-core" 

187 target_jtech = project_path / ".jtech-core" 

188 

189 if not source_jtech.exists(): 

190 console.print( 

191 "⚠️ Estrutura .jtech-core não encontrada nos assets", style="yellow" 

192 ) 

193 return 

194 

195 # Copiar toda a estrutura 

196 import shutil 

197 

198 if target_jtech.exists(): 

199 shutil.rmtree(target_jtech) 

200 

201 shutil.copytree(source_jtech, target_jtech) 

202 console.print("✅ Estrutura .jtech-core copiada dos assets", style="green") 

203 

204 

205def copy_chatmodes(project_path: Path): 

206 """Copia os chatmodes dos assets empacotados.""" 

207 assets_dir = Path(__file__).parent.parent / "assets" 

208 source_chatmodes = assets_dir / ".github" / "chatmodes" 

209 target_chatmodes = project_path / ".github" / "chatmodes" 

210 

211 if not source_chatmodes.exists(): 

212 console.print("⚠️ Chatmodes não encontrados nos assets", style="yellow") 

213 return 

214 

215 # Criar diretório target 

216 target_chatmodes.mkdir(parents=True, exist_ok=True) 

217 

218 # Copiar todos os arquivos .chatmode.md 

219 import shutil 

220 

221 copied_files = [] 

222 

223 for chatmode_file in source_chatmodes.glob("*.chatmode.md"): 

224 target_file = target_chatmodes / chatmode_file.name 

225 shutil.copy2(chatmode_file, target_file) 

226 copied_files.append(chatmode_file.name) 

227 

228 console.print( 

229 f"✅ Copiados {len(copied_files)} chatmodes dos assets", style="green" 

230 ) 

231 

232 

233def copy_vscode_config(project_path: Path): 

234 """Copia a configuração do VS Code dos assets empacotados.""" 

235 assets_dir = Path(__file__).parent.parent / "assets" 

236 source_vscode = assets_dir / ".vscode" / "settings.json" 

237 target_vscode_dir = project_path / ".vscode" 

238 target_vscode_file = target_vscode_dir / "settings.json" 

239 

240 if not source_vscode.exists(): 

241 console.print( 

242 "⚠️ Configuração VS Code não encontrada nos assets", style="yellow" 

243 ) 

244 return 

245 

246 # Criar diretório target 

247 target_vscode_dir.mkdir(parents=True, exist_ok=True) 

248 

249 # Copiar configuração 

250 import shutil 

251 

252 shutil.copy2(source_vscode, target_vscode_file) 

253 

254 console.print("✅ Configuração VS Code copiada dos assets", style="green") 

255 

256 

257def get_framework_source_path() -> Path: 

258 """Retorna o caminho para os arquivos fonte do framework.""" 

259 # Usar diretório de assets empacotados 

260 assets_dir = Path(__file__).parent.parent / "assets" 

261 return assets_dir 

262 

263 

264def validate_installation(project_path: Path, team_type: str): 

265 """Valida uma instalação existente.""" 

266 console.print("🔍 Validando instalação JTECH™ Core...", style="blue") 

267 

268 # Verificar se existe instalação 

269 jtech_core = project_path / ".jtech-core" 

270 if not jtech_core.exists(): 

271 console.print( 

272 "❌ Nenhuma instalação JTECH™ Core encontrada", style="red" 

273 ) 

274 console.print( 

275 "💡 Execute 'jtech-installer' para instalar", style="dim" 

276 ) 

277 return False 

278 

279 # Mapear tipo de equipe 

280 team_mapping = { 

281 "ide-minimal": TeamType.IDE_MINIMAL, 

282 "fullstack": TeamType.FULLSTACK, 

283 "no-ui": TeamType.NO_UI, 

284 "all": TeamType.ALL, 

285 } 

286 

287 # Criar configuração para validação 

288 config = InstallationConfig( 

289 project_path=project_path, 

290 install_type=InstallationType.BROWNFIELD, 

291 team_type=team_mapping[team_type], 

292 vs_code_integration=True, 

293 custom_config={}, 

294 framework_source_path=get_framework_source_path(), 

295 ) 

296 

297 # Executar validação 

298 with Progress( 

299 SpinnerColumn(), 

300 TextColumn("[progress.description]{task.description}"), 

301 console=console, 

302 ) as progress: 

303 task = progress.add_task("🔍 Executando validação...", total=None) 

304 

305 try: 

306 # Validação pós-instalação 

307 validator = PostInstallationValidator(config) 

308 report = validator.validate_all() 

309 

310 # Validação de integridade 

311 integrity_validator = IntegrityValidator(config) 

312 integrity_valid = integrity_validator.validate_all() 

313 

314 progress.remove_task(task) 

315 

316 except Exception as e: 

317 progress.remove_task(task) 

318 console.print(f"❌ Erro durante validação: {e}", style="red") 

319 return False 

320 

321 # Mostrar resultado da validação 

322 show_validation_result(report, integrity_valid, project_path) 

323 return report.is_valid 

324 

325 

326def show_installation_result(report, project_path: Path): 

327 """Mostra o resultado da instalação.""" 

328 

329 if report.is_valid: 

330 console.print( 

331 Panel.fit( 

332 "[bold green]🎉 INSTALAÇÃO CONCLUÍDA COM SUCESSO![/bold green]\n\n" 

333 f"📁 Projeto: [cyan]{project_path}[/cyan]\n" 

334 f"🔧 Estrutura: [green].jtech-core/[/green] criada\n" 

335 f"💬 ChatModes: [green].github/chatmodes/[/green] configurados\n" 

336 f"⚙️ VS Code: [green].vscode/settings.json[/green] configurado", 

337 title="✅ Sucesso", 

338 border_style="green", 

339 ) 

340 ) 

341 

342 # Mostrar próximos passos 

343 next_steps = Table(title="📋 Próximos Passos") 

344 next_steps.add_column("Comando", style="cyan") 

345 next_steps.add_column("Descrição", style="white") 

346 

347 next_steps.add_row("code .", "Abrir projeto no VS Code") 

348 next_steps.add_row( 

349 "jtech-installer --validate-only", "Validar instalação" 

350 ) 

351 next_steps.add_row("ls .jtech-core/", "Explorar estrutura criada") 

352 

353 console.print(next_steps) 

354 

355 else: 

356 invalid_components = [r for r in report.components if not r.is_valid] 

357 console.print( 

358 Panel.fit( 

359 "[bold yellow]⚠️ INSTALAÇÃO COM AVISOS[/bold yellow]\n\n" 

360 f"📁 Projeto: [cyan]{project_path}[/cyan]\n" 

361 f"🔍 Validações: [red]{len(invalid_components)}[/red] falharam", 

362 title="⚠️ Atenção", 

363 border_style="yellow", 

364 ) 

365 ) 

366 

367 

368def show_validation_result(report, integrity_valid: bool, project_path: Path): 

369 """Mostra o resultado da validação.""" 

370 

371 # Tabela de resultados 

372 table = Table(title="🔍 Resultado da Validação") 

373 table.add_column("Componente", style="cyan") 

374 table.add_column("Status", style="white") 

375 table.add_column("Detalhes", style="dim") 

376 

377 # Adicionar resultados individuais 

378 for result in report.components: 

379 status = "✅ OK" if result.is_valid else "❌ FALHA" 

380 table.add_row(result.component, status, result.message or "") 

381 

382 # Adicionar integridade 

383 integrity_status = "✅ OK" if integrity_valid else "❌ FALHA" 

384 table.add_row("Integridade", integrity_status, "Verificação de checksums") 

385 

386 console.print(table) 

387 

388 # Resultado geral 

389 if report.is_valid and integrity_valid: 

390 console.print( 

391 "\n🎉 [bold green]Instalação válida e íntegra![/bold green]" 

392 ) 

393 else: 

394 console.print( 

395 "\n⚠️ [bold yellow]Instalação com problemas detectados[/bold yellow]" 

396 ) 

397 

398 

399@cli.command() 

400def validate(): 

401 """Valida a instalação JTECH™ Core no diretório atual.""" 

402 project_path = Path.cwd() 

403 return validate_installation(project_path, "fullstack") 

404 

405 

406@cli.command() 

407@click.option( 

408 "--team", 

409 "-t", 

410 type=click.Choice(["ide-minimal", "fullstack", "no-ui", "all"]), 

411 default="fullstack", 

412) 

413def install(team): 

414 """Instala JTECH™ Core no diretório atual.""" 

415 project_path = Path.cwd() 

416 return install_jtech_core(project_path, team, force=False) 

417 

418 

419@cli.command() 

420@click.option( 

421 "--team", 

422 "-t", 

423 type=click.Choice(["ide-minimal", "fullstack", "no-ui", "all"]), 

424 default="fullstack", 

425) 

426def reinstall(team): 

427 """Reinstala JTECH™ Core (força reinstalação).""" 

428 project_path = Path.cwd() 

429 return install_jtech_core(project_path, team, force=True) 

430 

431 

432def main(): 

433 """Ponto de entrada principal.""" 

434 try: 

435 cli() 

436 except KeyboardInterrupt: 

437 console.print("\n❌ Operação cancelada pelo usuário", style="red") 

438 sys.exit(1) 

439 except Exception as e: 

440 console.print(f"\n❌ Erro inesperado: {e}", style="red") 

441 sys.exit(1) 

442 

443 

444if __name__ == "__main__": 

445 main()