@archznn/xavva 3.1.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -12
- package/package.json +3 -2
- package/src/commands/AuditCommand.ts +12 -10
- package/src/commands/BuildCommand.ts +9 -7
- package/src/commands/ChangelogCommand.ts +5 -5
- package/src/commands/CleanCommand.ts +242 -0
- package/src/commands/CompletionCommand.ts +7 -7
- package/src/commands/DbCommand.ts +43 -14
- package/src/commands/DeployCommand.ts +252 -229
- package/src/commands/DepsCommand.ts +174 -174
- package/src/commands/DockerCommand.ts +35 -4
- package/src/commands/DoctorCommand.ts +252 -239
- package/src/commands/EncodingCommand.ts +26 -19
- package/src/commands/HealthCommand.ts +7 -7
- package/src/commands/HelpCommand.ts +34 -14
- package/src/commands/HistoryCommand.ts +5 -5
- package/src/commands/HttpCommand.ts +27 -1
- package/src/commands/IdeCommand.ts +313 -0
- package/src/commands/InitCommand.ts +26 -25
- package/src/commands/LogsCommand.ts +8 -6
- package/src/commands/ProfilesCommand.ts +6 -6
- package/src/commands/RedoCommand.ts +2 -2
- package/src/commands/RunCommand.ts +64 -24
- package/src/commands/StartCommand.ts +9 -7
- package/src/commands/TestCommand.ts +25 -1
- package/src/commands/TomcatCommand.ts +232 -88
- package/src/config/versions.ts +111 -9
- package/src/di/container.ts +239 -105
- package/src/errors/ErrorHandler.ts +23 -19
- package/src/errors/errorMessages.ts +235 -0
- package/src/index.ts +20 -6
- package/src/logging/FileLogger.ts +235 -0
- package/src/logging/Logger.ts +545 -0
- package/src/logging/OperationLogger.ts +296 -0
- package/src/logging/ProgressLogger.ts +187 -0
- package/src/logging/TableLogger.ts +246 -0
- package/src/logging/colors.ts +167 -0
- package/src/logging/constants.ts +176 -0
- package/src/logging/formatters.ts +337 -0
- package/src/logging/index.ts +93 -0
- package/src/logging/types.ts +64 -0
- package/src/plugins/PluginManager.ts +325 -0
- package/src/plugins/types.ts +82 -0
- package/src/services/AuditService.ts +5 -3
- package/src/services/BuildService.ts +15 -17
- package/src/services/DashboardService.ts +14 -3
- package/src/services/DbService.ts +35 -34
- package/src/services/DependencyAnalyzerService.ts +18 -18
- package/src/services/DependencyCacheService.ts +303 -0
- package/src/services/DeployWatcher.ts +127 -23
- package/src/services/DockerService.ts +3 -3
- package/src/services/EmbeddedTomcatService.ts +13 -12
- package/src/services/FileWatcher.ts +15 -7
- package/src/services/HttpService.ts +5 -5
- package/src/services/LogAnalyzer.ts +26 -22
- package/src/services/PerformanceProfiler.ts +267 -0
- package/src/services/ProjectService.ts +3 -0
- package/src/services/TestService.ts +3 -3
- package/src/services/TomcatService.ts +46 -25
- package/src/services/tomcat/TomcatBackupManager.ts +330 -0
- package/src/services/tomcat/TomcatChecksumVerifier.ts +211 -0
- package/src/services/tomcat/TomcatCompatibilityChecker.ts +298 -0
- package/src/services/tomcat/TomcatDownloadCache.ts +250 -0
- package/src/services/tomcat/TomcatDownloadService.ts +335 -0
- package/src/services/tomcat/TomcatInstallerService.ts +474 -0
- package/src/services/tomcat/TomcatMirrorManager.ts +181 -0
- package/src/services/tomcat/index.ts +36 -0
- package/src/services/tomcat/types.ts +120 -0
- package/src/types/args.ts +68 -1
- package/src/types/configSchema.ts +174 -0
- package/src/utils/ChangelogGenerator.ts +11 -11
- package/src/utils/LoggerLevel.ts +44 -20
- package/src/utils/ProgressBar.ts +87 -46
- package/src/utils/argsParser.ts +260 -0
- package/src/utils/config.ts +340 -189
- package/src/utils/constants.ts +87 -9
- package/src/utils/dryRun.ts +192 -0
- package/src/utils/processManager.ts +23 -7
- package/src/utils/security.ts +293 -0
- package/src/utils/ui.ts +299 -428
package/src/utils/config.ts
CHANGED
|
@@ -1,97 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gerenciamento de configuração do XAVVA CLI
|
|
3
|
+
*
|
|
4
|
+
* Responsabilidades:
|
|
5
|
+
* - Parse de argumentos CLI
|
|
6
|
+
* - Load de xavva.json
|
|
7
|
+
* - Setup de Tomcat embutido
|
|
8
|
+
* - Merge de configurações (CLI > xavva.json > env > defaults)
|
|
9
|
+
* - Validação com Zod
|
|
10
|
+
*/
|
|
11
|
+
|
|
1
12
|
import { parseArgs } from "util";
|
|
2
13
|
import path from "path";
|
|
3
14
|
import fs from "fs";
|
|
4
|
-
import {
|
|
15
|
+
import { PORTS } from "../config/versions";
|
|
5
16
|
import type { AppConfig, CLIArguments, CommandContext } from "../types/config";
|
|
6
17
|
import { EmbeddedTomcatService } from "../services/EmbeddedTomcatService";
|
|
7
|
-
import { Logger } from "./ui";
|
|
18
|
+
import { Logger, C } from "./ui";
|
|
19
|
+
import { validateAppConfig, validatePort, type ValidatedAppConfig } from "../types/configSchema";
|
|
20
|
+
|
|
21
|
+
// Parse options extraídas para reuso
|
|
22
|
+
const PARSE_OPTIONS = {
|
|
23
|
+
path: { type: "string" as const, short: "p" },
|
|
24
|
+
tool: { type: "string" as const, short: "t" },
|
|
25
|
+
name: { type: "string" as const, short: "n" },
|
|
26
|
+
port: { type: "string" as const },
|
|
27
|
+
"no-build": { type: "boolean" as const, short: "s" },
|
|
28
|
+
scan: { type: "boolean" as const },
|
|
29
|
+
clean: { type: "boolean" as const, short: "c" },
|
|
30
|
+
quiet: { type: "boolean" as const, short: "q" },
|
|
31
|
+
help: { type: "boolean" as const, short: "h" },
|
|
32
|
+
version: { type: "boolean" as const, short: "v" },
|
|
33
|
+
debug: { type: "boolean" as const, short: "d" },
|
|
34
|
+
watch: { type: "boolean" as const, short: "w" },
|
|
35
|
+
profile: { type: "string" as const, short: "P" },
|
|
36
|
+
grep: { type: "string" as const, short: "G" },
|
|
37
|
+
verbose: { type: "boolean" as const, short: "V" },
|
|
38
|
+
encoding: { type: "string" as const, short: "e" },
|
|
39
|
+
dp: { type: "string" as const },
|
|
40
|
+
fix: { type: "boolean" as const },
|
|
41
|
+
tui: { type: "boolean" as const },
|
|
42
|
+
output: { type: "string" as const, short: "o" },
|
|
43
|
+
strict: { type: "boolean" as const },
|
|
44
|
+
"tomcat-version": { type: "string" as const },
|
|
45
|
+
yes: { type: "boolean" as const, short: "y" },
|
|
46
|
+
war: { type: "boolean" as const, short: "W" },
|
|
47
|
+
cache: { type: "boolean" as const },
|
|
48
|
+
from: { type: "string" as const },
|
|
49
|
+
to: { type: "string" as const },
|
|
50
|
+
backup: { type: "boolean" as const },
|
|
51
|
+
"dry-run": { type: "boolean" as const },
|
|
52
|
+
force: { type: "boolean" as const },
|
|
53
|
+
src: { type: "string" as const },
|
|
54
|
+
env: { type: "string" as const },
|
|
55
|
+
environment: { type: "string" as const },
|
|
56
|
+
coverage: { type: "boolean" as const },
|
|
57
|
+
"fail-fast": { type: "boolean" as const },
|
|
58
|
+
parallel: { type: "boolean" as const },
|
|
59
|
+
interactive: { type: "boolean" as const, short: "i" },
|
|
60
|
+
"base-url": { type: "string" as const },
|
|
61
|
+
body: { type: "string" as const },
|
|
62
|
+
file: { type: "string" as const },
|
|
63
|
+
header: { type: "string" as const, multiple: true },
|
|
64
|
+
"content-type": { type: "string" as const },
|
|
65
|
+
accept: { type: "string" as const },
|
|
66
|
+
param: { type: "string" as const, multiple: true },
|
|
67
|
+
timeout: { type: "string" as const },
|
|
68
|
+
tag: { type: "string" as const },
|
|
69
|
+
"java-version": { type: "string" as const },
|
|
70
|
+
detached: { type: "boolean" as const, short: "d" },
|
|
71
|
+
registry: { type: "string" as const },
|
|
72
|
+
namespace: { type: "string" as const },
|
|
73
|
+
// Clean command
|
|
74
|
+
all: { type: "boolean" as const },
|
|
75
|
+
build: { type: "boolean" as const },
|
|
76
|
+
// IDE command
|
|
77
|
+
ide: { type: "string" as const },
|
|
78
|
+
};
|
|
8
79
|
|
|
9
80
|
export class ConfigManager {
|
|
81
|
+
/**
|
|
82
|
+
* Carrega e valida configuração completa
|
|
83
|
+
*/
|
|
10
84
|
static async load(): Promise<CommandContext> {
|
|
11
|
-
const
|
|
85
|
+
const argv = this.getArgv();
|
|
86
|
+
const { values, positionals } = this.parseCliArgs(argv);
|
|
87
|
+
const cliValues = values as CLIArguments;
|
|
88
|
+
|
|
89
|
+
// Detectar contexto
|
|
90
|
+
const commandContext = this.detectCommandContext(positionals);
|
|
12
91
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
quiet: { type: "boolean", short: "q" },
|
|
24
|
-
help: { type: "boolean", short: "h" },
|
|
25
|
-
version: { type: "boolean", short: "v" },
|
|
26
|
-
debug: { type: "boolean", short: "d" },
|
|
27
|
-
watch: { type: "boolean", short: "w" },
|
|
28
|
-
profile: { type: "string", short: "P" },
|
|
29
|
-
grep: { type: "string", short: "G" },
|
|
30
|
-
verbose: { type: "boolean", short: "V" },
|
|
31
|
-
encoding: { type: "string", short: "e" },
|
|
32
|
-
dp: { type: "string" },
|
|
33
|
-
fix: { type: "boolean" },
|
|
34
|
-
tui: { type: "boolean" },
|
|
35
|
-
output: { type: "string", short: "o" },
|
|
36
|
-
strict: { type: "boolean" },
|
|
37
|
-
"tomcat-version": { type: "string" },
|
|
38
|
-
yes: { type: "boolean", short: "y" },
|
|
39
|
-
war: { type: "boolean", short: "W" },
|
|
40
|
-
cache: { type: "boolean" },
|
|
41
|
-
from: { type: "string" },
|
|
42
|
-
to: { type: "string" },
|
|
43
|
-
backup: { type: "boolean" },
|
|
44
|
-
"dry-run": { type: "boolean" },
|
|
45
|
-
force: { type: "boolean" },
|
|
46
|
-
src: { type: "string" },
|
|
47
|
-
// Multi-environment
|
|
48
|
-
env: { type: "string" },
|
|
49
|
-
environment: { type: "string" },
|
|
50
|
-
// Test runner
|
|
51
|
-
coverage: { type: "boolean" },
|
|
52
|
-
"fail-fast": { type: "boolean" },
|
|
53
|
-
parallel: { type: "boolean" },
|
|
54
|
-
// HTTP client
|
|
55
|
-
interactive: { type: "boolean", short: "i" },
|
|
56
|
-
"base-url": { type: "string" },
|
|
57
|
-
body: { type: "string" },
|
|
58
|
-
file: { type: "string" },
|
|
59
|
-
header: { type: "string", multiple: true },
|
|
60
|
-
"content-type": { type: "string" },
|
|
61
|
-
accept: { type: "string" },
|
|
62
|
-
param: { type: "string", multiple: true },
|
|
63
|
-
timeout: { type: "string" },
|
|
64
|
-
// Docker
|
|
65
|
-
tag: { type: "string" },
|
|
66
|
-
"java-version": { type: "string" },
|
|
67
|
-
detached: { type: "boolean", short: "d" },
|
|
68
|
-
registry: { type: "string" },
|
|
69
|
-
namespace: { type: "string" },
|
|
70
|
-
},
|
|
71
|
-
strict: false,
|
|
72
|
-
allowPositionals: true,
|
|
92
|
+
// Carregar configs de diferentes fontes
|
|
93
|
+
const fileConfig = await this.loadConfigFile();
|
|
94
|
+
const envConfig = this.loadEnvConfig();
|
|
95
|
+
|
|
96
|
+
// Merge de configurações (prioridade: CLI > env > file > defaults)
|
|
97
|
+
const mergedConfig = await this.mergeConfigurations({
|
|
98
|
+
cli: cliValues,
|
|
99
|
+
file: fileConfig,
|
|
100
|
+
env: envConfig,
|
|
101
|
+
context: commandContext,
|
|
73
102
|
});
|
|
74
103
|
|
|
75
|
-
|
|
104
|
+
// Setup de Tomcat embutido se necessário
|
|
105
|
+
const finalConfig = await this.setupTomcatIfNeeded(mergedConfig, cliValues, commandContext);
|
|
76
106
|
|
|
77
|
-
//
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
} catch (e) {
|
|
84
|
-
console.error("Error reading xavva.json:", (e as Error).message);
|
|
85
|
-
}
|
|
107
|
+
// Validar configuração final
|
|
108
|
+
const validatedConfig = this.validateConfig(finalConfig);
|
|
109
|
+
|
|
110
|
+
// Ajustes baseados no comando
|
|
111
|
+
if (commandContext.isDev) {
|
|
112
|
+
cliValues.watch = true;
|
|
86
113
|
}
|
|
87
114
|
|
|
115
|
+
this.ensureGitIgnore();
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
config: validatedConfig,
|
|
119
|
+
positionals,
|
|
120
|
+
values: cliValues
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Obtém argumentos do processo
|
|
126
|
+
*/
|
|
127
|
+
private static getArgv(): string[] {
|
|
128
|
+
const isBun = Bun.argv[0].endsWith("bun.exe") || Bun.argv[0].endsWith("bun");
|
|
129
|
+
return Bun.argv.slice(isBun ? 2 : 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Parse de argumentos CLI
|
|
134
|
+
*/
|
|
135
|
+
private static parseCliArgs(argv: string[]) {
|
|
136
|
+
return parseArgs({
|
|
137
|
+
args: argv,
|
|
138
|
+
options: PARSE_OPTIONS,
|
|
139
|
+
strict: false,
|
|
140
|
+
allowPositionals: true,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Detecta contexto do comando atual
|
|
146
|
+
*/
|
|
147
|
+
private static detectCommandContext(positionals: string[]) {
|
|
88
148
|
const isDev = positionals.includes("dev");
|
|
89
149
|
const isRun = positionals.includes("run") || positionals.includes("debug");
|
|
90
150
|
const isStart = positionals.includes("start") || positionals.includes("deploy") || isDev;
|
|
91
151
|
|
|
92
|
-
const envTomcatPath = process.env.TOMCAT_HOME || process.env.CATALINA_HOME;
|
|
93
|
-
const detectedTool = this.detectBuildTool();
|
|
94
|
-
|
|
95
152
|
let runClass = "";
|
|
96
153
|
if (isRun) {
|
|
97
154
|
const runIdx = positionals.indexOf("run");
|
|
@@ -100,151 +157,243 @@ export class ConfigManager {
|
|
|
100
157
|
runClass = positionals[idx + 1] || "";
|
|
101
158
|
}
|
|
102
159
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
version: embeddedVersion,
|
|
120
|
-
port: parseInt(String(cliValues.port || xavvaJson.port || String(DEFAULT_TOMCAT_PORT))),
|
|
121
|
-
webappPath: webappPath
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// Instala se necessário
|
|
125
|
-
if (!embeddedService.checkInstallation()) {
|
|
126
|
-
Logger.newline();
|
|
127
|
-
Logger.warn("Tomcat não encontrado!");
|
|
128
|
-
Logger.info("Versão solicitada", embeddedVersion);
|
|
129
|
-
Logger.newline();
|
|
130
|
-
Logger.log(`${Logger.C.primary}?${Logger.C.reset} Deseja instalar o Tomcat ${embeddedVersion} automaticamente?`);
|
|
131
|
-
Logger.log(`${Logger.C.dim} O download é de ~16MB e será salvo em:~/.xavva/tomcat/${embeddedVersion}${Logger.C.reset}`);
|
|
132
|
-
Logger.newline();
|
|
133
|
-
|
|
134
|
-
// Garante que não há output pendente antes da pergunta
|
|
135
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
136
|
-
process.stdout.write('\r\x1b[K'); // Limpa linha atual
|
|
137
|
-
|
|
138
|
-
const autoYes = !!cliValues.yes;
|
|
139
|
-
const shouldInstall = autoYes || await this.askYesNo("Instalar");
|
|
140
|
-
|
|
141
|
-
if (!shouldInstall) {
|
|
142
|
-
Logger.newline();
|
|
143
|
-
Logger.info("Opções disponíveis", "");
|
|
144
|
-
Logger.log(` ${Logger.C.primary}1.${Logger.C.reset} Defina TOMCAT_HOME ou CATALINA_HOME`);
|
|
145
|
-
Logger.log(` ${Logger.C.primary}2.${Logger.C.reset} Use --path para especificar o Tomcat`);
|
|
146
|
-
Logger.log(` ${Logger.C.primary}3.${Logger.C.reset} Use --tomcat-version para outra versão`);
|
|
147
|
-
Logger.newline();
|
|
148
|
-
process.exit(0);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
Logger.newline();
|
|
152
|
-
const installed = await embeddedService.install();
|
|
153
|
-
if (!installed) {
|
|
154
|
-
Logger.error("Falha ao instalar Tomcat embutido.");
|
|
155
|
-
Logger.info("Dica", "Instale o Tomcat manualmente ou defina TOMCAT_HOME");
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
Logger.info("Tomcat", `Usando versão embutida ${embeddedVersion}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Configura contexto da aplicação
|
|
163
|
-
await embeddedService.createAppContext();
|
|
164
|
-
|
|
165
|
-
tomcatPath = embeddedService.getTomcatHome();
|
|
160
|
+
return {
|
|
161
|
+
isDev,
|
|
162
|
+
isRun,
|
|
163
|
+
isStart,
|
|
164
|
+
runClass,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Carrega configuração do arquivo xavva.json
|
|
170
|
+
*/
|
|
171
|
+
private static async loadConfigFile(): Promise<Partial<CLIArguments>> {
|
|
172
|
+
const xavvaJsonPath = path.join(process.cwd(), "xavva.json");
|
|
173
|
+
|
|
174
|
+
if (!fs.existsSync(xavvaJsonPath)) {
|
|
175
|
+
return {};
|
|
166
176
|
}
|
|
167
177
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
178
|
+
try {
|
|
179
|
+
const content = fs.readFileSync(xavvaJsonPath, "utf8");
|
|
180
|
+
return JSON.parse(content);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
console.error("Erro ao ler xavva.json:", (e as Error).message);
|
|
183
|
+
return {};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Carrega configuração de variáveis de ambiente
|
|
189
|
+
*/
|
|
190
|
+
private static loadEnvConfig(): { tomcatPath?: string } {
|
|
191
|
+
return {
|
|
192
|
+
tomcatPath: process.env.TOMCAT_HOME || process.env.CATALINA_HOME,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
171
195
|
|
|
172
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Detecta build tool do projeto
|
|
198
|
+
*/
|
|
199
|
+
private static detectBuildTool(): "maven" | "gradle" {
|
|
200
|
+
const cwd = process.cwd();
|
|
201
|
+
|
|
202
|
+
if (fs.existsSync(path.join(cwd, "pom.xml"))) {
|
|
203
|
+
return "maven";
|
|
204
|
+
}
|
|
205
|
+
if (fs.existsSync(path.join(cwd, "build.gradle")) ||
|
|
206
|
+
fs.existsSync(path.join(cwd, "build.gradle.kts"))) {
|
|
207
|
+
return "gradle";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return "maven";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Merge de todas as configurações
|
|
215
|
+
*/
|
|
216
|
+
private static async mergeConfigurations({
|
|
217
|
+
cli,
|
|
218
|
+
file,
|
|
219
|
+
env,
|
|
220
|
+
context,
|
|
221
|
+
}: {
|
|
222
|
+
cli: CLIArguments;
|
|
223
|
+
file: Partial<CLIArguments>;
|
|
224
|
+
env: { tomcatPath?: string };
|
|
225
|
+
context: { isDev: boolean; isRun: boolean; isStart: boolean; runClass: string };
|
|
226
|
+
}): Promise<AppConfig> {
|
|
227
|
+
const detectedTool = this.detectBuildTool();
|
|
228
|
+
const environment = String(cli.env || cli.environment || file.env || file.environment || "");
|
|
229
|
+
const envConfig = environment && (file as any).environments?.[environment];
|
|
230
|
+
|
|
231
|
+
// Versão do Tomcat
|
|
232
|
+
const xavvaTomcatVersion = (file as any).tomcat?.version;
|
|
233
|
+
const embeddedVersion = String(cli["tomcat-version"] || xavvaTomcatVersion || file.version || "10.1.52");
|
|
234
|
+
|
|
235
|
+
// Porta
|
|
173
236
|
const finalPort = envConfig?.port
|
|
174
|
-
?
|
|
175
|
-
:
|
|
176
|
-
const finalProfile = envConfig?.profile || String(cliValues.profile || xavvaJson.profile || "");
|
|
237
|
+
? validatePort(envConfig.port)
|
|
238
|
+
: validatePort(cli.port || file.port || PORTS.DEFAULT_TOMCAT);
|
|
177
239
|
|
|
178
|
-
|
|
240
|
+
// Profile
|
|
241
|
+
const finalProfile = envConfig?.profile || String(cli.profile || file.profile || "");
|
|
242
|
+
|
|
243
|
+
// Tomcat path
|
|
244
|
+
let tomcatPath = String(cli.path || file.path || env.tomcatPath || "");
|
|
245
|
+
|
|
246
|
+
return {
|
|
179
247
|
tomcat: {
|
|
180
248
|
path: tomcatPath,
|
|
181
249
|
port: finalPort,
|
|
182
250
|
webapps: "webapps",
|
|
183
|
-
grep:
|
|
184
|
-
embedded:
|
|
251
|
+
grep: cli.grep || file.grep ? String(cli.grep || file.grep) : "",
|
|
252
|
+
embedded: false, // Será atualizado no setupTomcatIfNeeded
|
|
185
253
|
version: embeddedVersion,
|
|
186
|
-
...(envConfig?.tomcat || {})
|
|
254
|
+
...(envConfig?.tomcat || {}),
|
|
187
255
|
},
|
|
188
256
|
project: {
|
|
189
|
-
appName:
|
|
190
|
-
buildTool: (
|
|
257
|
+
appName: cli.name || file.name ? String(cli.name || file.name) : "",
|
|
258
|
+
buildTool: (cli.tool as any) || (file.tool as any) || detectedTool,
|
|
191
259
|
profile: finalProfile,
|
|
192
|
-
skipBuild: !!(
|
|
193
|
-
skipScan:
|
|
194
|
-
clean: !!(
|
|
195
|
-
cleanLogs: (
|
|
196
|
-
quiet: (
|
|
197
|
-
verbose: !!(
|
|
198
|
-
debug: !!(
|
|
199
|
-
debugPort:
|
|
200
|
-
grep: runClass || (
|
|
201
|
-
tui: !!(
|
|
202
|
-
encoding:
|
|
203
|
-
war: !!(
|
|
204
|
-
cache: !!(
|
|
260
|
+
skipBuild: !!(cli["no-build"] ?? file["no-build"]),
|
|
261
|
+
skipScan: cli.scan !== undefined ? !cli.scan : (file.scan !== undefined ? !file.scan : true),
|
|
262
|
+
clean: !!(cli.clean ?? file.clean),
|
|
263
|
+
cleanLogs: (cli.verbose ?? file.verbose) ? false : true,
|
|
264
|
+
quiet: (cli.verbose ?? file.verbose) ? false : true,
|
|
265
|
+
verbose: !!(cli.verbose ?? file.verbose),
|
|
266
|
+
debug: !!(cli.debug ?? file.debug ?? context.isDev ?? context.isRun),
|
|
267
|
+
debugPort: validatePort(cli.dp || file.dp || PORTS.DEFAULT_DEBUG),
|
|
268
|
+
grep: context.runClass || (cli.grep || file.grep ? String(cli.grep || file.grep) : ""),
|
|
269
|
+
tui: !!(cli.tui ?? file.tui),
|
|
270
|
+
encoding: cli.encoding || file.encoding || "",
|
|
271
|
+
war: !!(cli.war ?? file.war),
|
|
272
|
+
cache: !!(cli.cache ?? file.cache),
|
|
205
273
|
environment,
|
|
206
|
-
environments: (
|
|
274
|
+
environments: (file as any).environments,
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Setup de Tomcat embutido se necessário
|
|
281
|
+
*/
|
|
282
|
+
private static async setupTomcatIfNeeded(
|
|
283
|
+
config: AppConfig,
|
|
284
|
+
cliValues: CLIArguments,
|
|
285
|
+
context: { isStart: boolean }
|
|
286
|
+
): Promise<AppConfig> {
|
|
287
|
+
const hasCatalina = fs.existsSync(path.join(config.tomcat.path, "bin", "catalina.bat")) ||
|
|
288
|
+
fs.existsSync(path.join(config.tomcat.path, "bin", "catalina.sh"));
|
|
289
|
+
|
|
290
|
+
// Se já tem Tomcat válido ou não precisa iniciar, retorna config atual
|
|
291
|
+
if ((config.tomcat.path && hasCatalina) || !context.isStart) {
|
|
292
|
+
return config;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Usar Tomcat embutido
|
|
296
|
+
const embeddedService = new EmbeddedTomcatService({
|
|
297
|
+
version: config.tomcat.version,
|
|
298
|
+
port: config.tomcat.port,
|
|
299
|
+
webappPath: path.join(process.cwd(), "src", "main", "webapp"),
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
if (!embeddedService.checkInstallation()) {
|
|
303
|
+
const shouldInstall = await this.promptForTomcatInstall(config.tomcat.version, cliValues.yes);
|
|
304
|
+
|
|
305
|
+
if (!shouldInstall) {
|
|
306
|
+
this.printTomcatHelp();
|
|
307
|
+
process.exit(0);
|
|
207
308
|
}
|
|
309
|
+
|
|
310
|
+
const installed = await embeddedService.install();
|
|
311
|
+
if (!installed) {
|
|
312
|
+
Logger.error("Falha ao instalar Tomcat embutido.");
|
|
313
|
+
Logger.info("Dica", "Instale o Tomcat manualmente ou defina TOMCAT_HOME");
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
Logger.info("Tomcat", `Usando versão embutida ${config.tomcat.version}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
await embeddedService.createAppContext();
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
...config,
|
|
324
|
+
tomcat: {
|
|
325
|
+
...config.tomcat,
|
|
326
|
+
path: embeddedService.getTomcatHome(),
|
|
327
|
+
embedded: true,
|
|
328
|
+
},
|
|
208
329
|
};
|
|
330
|
+
}
|
|
209
331
|
|
|
210
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Prompt para instalação do Tomcat
|
|
334
|
+
*/
|
|
335
|
+
private static async promptForTomcatInstall(version: string, autoYes?: boolean): Promise<boolean> {
|
|
336
|
+
Logger.newline();
|
|
337
|
+
Logger.warn("Tomcat não encontrado!");
|
|
338
|
+
Logger.info("Versão solicitada", version);
|
|
339
|
+
Logger.newline();
|
|
340
|
+
Logger.log(`${C.primary}?${C.reset} Deseja instalar o Tomcat ${version} automaticamente?`);
|
|
341
|
+
Logger.log(`${C.dim} O download é de ~16MB e será salvo em:~/.xavva/tomcat/${version}${C.reset}`);
|
|
342
|
+
Logger.newline();
|
|
211
343
|
|
|
212
|
-
|
|
344
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
345
|
+
process.stdout.write('\r\x1b[K');
|
|
346
|
+
|
|
347
|
+
if (autoYes) return true;
|
|
213
348
|
|
|
214
|
-
return
|
|
349
|
+
return this.askYesNo("Instalar");
|
|
215
350
|
}
|
|
216
351
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Print opções de ajuda para Tomcat
|
|
354
|
+
*/
|
|
355
|
+
private static printTomcatHelp(): void {
|
|
356
|
+
Logger.newline();
|
|
357
|
+
Logger.info("Opções disponíveis", "");
|
|
358
|
+
Logger.log(` ${C.primary}1.${C.reset} Defina TOMCAT_HOME ou CATALINA_HOME`);
|
|
359
|
+
Logger.log(` ${C.primary}2.${C.reset} Use --path para especificar o Tomcat`);
|
|
360
|
+
Logger.log(` ${C.primary}3.${C.reset} Use --tomcat-version para outra versão`);
|
|
361
|
+
Logger.newline();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Valida configuração com Zod
|
|
366
|
+
*/
|
|
367
|
+
private static validateConfig(config: AppConfig): AppConfig {
|
|
368
|
+
try {
|
|
369
|
+
return validateAppConfig(config);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
Logger.error("Configuração inválida:");
|
|
372
|
+
Logger.error((error as Error).message);
|
|
373
|
+
process.exit(1);
|
|
223
374
|
}
|
|
224
|
-
return "maven";
|
|
225
375
|
}
|
|
226
376
|
|
|
377
|
+
/**
|
|
378
|
+
* Prompt yes/no
|
|
379
|
+
*/
|
|
227
380
|
private static async askYesNo(question: string): Promise<boolean> {
|
|
228
|
-
// Pequeno delay para garantir que o output anterior foi processado
|
|
229
381
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
230
|
-
|
|
231
|
-
// Limpa qualquer coisa pendente no stdout
|
|
232
382
|
process.stdout.write('\x1b[0m');
|
|
233
|
-
|
|
383
|
+
|
|
234
384
|
return new Promise((resolve) => {
|
|
235
385
|
const chunks: Buffer[] = [];
|
|
236
|
-
|
|
386
|
+
|
|
237
387
|
const cleanup = () => {
|
|
238
388
|
process.stdin.removeListener('data', onData);
|
|
239
389
|
process.stdin.removeListener('end', onEnd);
|
|
240
390
|
process.stdin.pause();
|
|
241
391
|
};
|
|
242
|
-
|
|
392
|
+
|
|
243
393
|
const onData = (data: Buffer) => {
|
|
244
394
|
chunks.push(data);
|
|
245
395
|
const str = Buffer.concat(chunks).toString();
|
|
246
|
-
|
|
247
|
-
// Procura por enter no input
|
|
396
|
+
|
|
248
397
|
if (str.includes('\n') || str.includes('\r')) {
|
|
249
398
|
cleanup();
|
|
250
399
|
const answer = str.replace(/\r?\n/g, '').trim().toLowerCase();
|
|
@@ -252,23 +401,24 @@ export class ConfigManager {
|
|
|
252
401
|
resolve(answer === '' || answer === 'y' || answer === 'yes');
|
|
253
402
|
}
|
|
254
403
|
};
|
|
255
|
-
|
|
404
|
+
|
|
256
405
|
const onEnd = () => {
|
|
257
406
|
cleanup();
|
|
258
407
|
const answer = Buffer.concat(chunks).toString().trim().toLowerCase();
|
|
259
408
|
resolve(answer === '' || answer === 'y' || answer === 'yes');
|
|
260
409
|
};
|
|
261
|
-
|
|
262
|
-
// Mostra a pergunta
|
|
410
|
+
|
|
263
411
|
process.stdout.write(`${question} [Y/n]: `);
|
|
264
|
-
|
|
265
412
|
process.stdin.resume();
|
|
266
413
|
process.stdin.on('data', onData);
|
|
267
414
|
process.stdin.on('end', onEnd);
|
|
268
415
|
});
|
|
269
416
|
}
|
|
270
417
|
|
|
271
|
-
|
|
418
|
+
/**
|
|
419
|
+
* Garante que .xavva está no .gitignore
|
|
420
|
+
*/
|
|
421
|
+
private static ensureGitIgnore(): void {
|
|
272
422
|
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
273
423
|
|
|
274
424
|
if (!fs.existsSync(gitignorePath)) return;
|
|
@@ -280,6 +430,7 @@ export class ConfigManager {
|
|
|
280
430
|
fs.writeFileSync(gitignorePath, newContent);
|
|
281
431
|
}
|
|
282
432
|
} catch (e) {
|
|
433
|
+
// Silently fail
|
|
283
434
|
}
|
|
284
435
|
}
|
|
285
436
|
}
|