@archznn/xavva 1.7.0 → 1.8.1
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 +95 -25
- package/package.json +1 -1
- package/src/commands/AuditCommand.ts +6 -6
- package/src/commands/BuildCommand.ts +3 -3
- package/src/commands/Command.ts +2 -2
- package/src/commands/CommandRegistry.ts +36 -0
- package/src/commands/DeployCommand.ts +146 -116
- package/src/commands/DoctorCommand.ts +105 -5
- package/src/commands/HelpCommand.ts +2 -1
- package/src/commands/RunCommand.ts +112 -36
- package/src/commands/StartCommand.ts +3 -1
- package/src/index.ts +42 -133
- package/src/services/AuditService.ts +7 -2
- package/src/services/BrowserService.ts +41 -0
- package/src/services/BuildCacheService.ts +83 -0
- package/src/services/BuildService.ts +105 -82
- package/src/services/EndpointService.ts +17 -0
- package/src/services/ProjectService.ts +126 -0
- package/src/services/TomcatService.ts +65 -67
- package/src/services/WatcherService.ts +78 -0
- package/src/types/config.ts +30 -1
- package/src/utils/config.ts +21 -17
- package/src/utils/ui.ts +15 -13
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import crypto from "crypto";
|
|
4
|
+
|
|
5
|
+
export interface CacheData {
|
|
6
|
+
lastConfigHash: string;
|
|
7
|
+
lastBuildTime: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class BuildCacheService {
|
|
11
|
+
private cacheDir: string;
|
|
12
|
+
private cacheFile: string;
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.cacheDir = path.join(process.cwd(), ".xavva");
|
|
16
|
+
this.cacheFile = path.join(this.cacheDir, "build-cache.json");
|
|
17
|
+
if (!fs.existsSync(this.cacheDir)) {
|
|
18
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getHash(filePath: string): string {
|
|
23
|
+
if (!fs.existsSync(filePath)) return "";
|
|
24
|
+
const content = fs.readFileSync(filePath);
|
|
25
|
+
return crypto.createHash("md5").update(content).digest("hex");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getConfigHash(tool: "maven" | "gradle"): string {
|
|
29
|
+
const file = tool === "maven" ? "pom.xml" : "build.gradle";
|
|
30
|
+
const configPath = path.join(process.cwd(), file);
|
|
31
|
+
let hash = this.getHash(configPath);
|
|
32
|
+
|
|
33
|
+
// Se for gradle, também checar build.gradle.kts e settings
|
|
34
|
+
if (tool === "gradle") {
|
|
35
|
+
const kts = path.join(process.cwd(), "build.gradle.kts");
|
|
36
|
+
const settings = path.join(process.cwd(), "settings.gradle");
|
|
37
|
+
if (fs.existsSync(kts)) hash += this.getHash(kts);
|
|
38
|
+
if (fs.existsSync(settings)) hash += this.getHash(settings);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return crypto.createHash("md5").update(hash).digest("hex");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
shouldRebuild(tool: "maven" | "gradle", projectService?: any): boolean {
|
|
45
|
+
if (!fs.existsSync(this.cacheFile)) return true;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const currentHash = this.getConfigHash(tool);
|
|
49
|
+
const cache: CacheData = JSON.parse(fs.readFileSync(this.cacheFile, "utf-8"));
|
|
50
|
+
|
|
51
|
+
// Se o pom/gradle mudou, precisa de rebuild completo
|
|
52
|
+
if (currentHash !== cache.lastConfigHash) return true;
|
|
53
|
+
|
|
54
|
+
// Verificar se o artefato (.war) ainda existe fisicamente
|
|
55
|
+
if (projectService) {
|
|
56
|
+
try {
|
|
57
|
+
const artifact = projectService.getArtifact();
|
|
58
|
+
if (!fs.existsSync(artifact.path)) return true;
|
|
59
|
+
} catch (e) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
} catch (e) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
saveCache(tool: "maven" | "gradle") {
|
|
71
|
+
const data: CacheData = {
|
|
72
|
+
lastConfigHash: this.getConfigHash(tool),
|
|
73
|
+
lastBuildTime: Date.now()
|
|
74
|
+
};
|
|
75
|
+
fs.writeFileSync(this.cacheFile, JSON.stringify(data, null, 2));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
clearCache() {
|
|
79
|
+
if (fs.existsSync(this.cacheFile)) {
|
|
80
|
+
fs.unlinkSync(this.cacheFile);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -1,47 +1,78 @@
|
|
|
1
|
-
import { readdirSync,
|
|
1
|
+
import { readdirSync, existsSync, statSync, mkdirSync, promises as fs } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import type { ProjectConfig, TomcatConfig } from "../types/config";
|
|
4
4
|
import { Logger } from "../utils/ui";
|
|
5
|
+
import { BuildCacheService } from "./BuildCacheService";
|
|
6
|
+
import { ProjectService } from "./ProjectService";
|
|
5
7
|
|
|
6
8
|
export class BuildService {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
constructor(
|
|
10
|
+
private projectConfig: ProjectConfig,
|
|
11
|
+
private tomcatConfig: TomcatConfig,
|
|
12
|
+
private projectService: ProjectService,
|
|
13
|
+
private cache: BuildCacheService
|
|
14
|
+
) { }
|
|
10
15
|
|
|
11
16
|
async runBuild(incremental = false) {
|
|
17
|
+
if (this.projectConfig.clean) {
|
|
18
|
+
this.cache.clearCache();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!incremental && !this.projectConfig.skipBuild) {
|
|
22
|
+
if (!this.projectConfig.clean && !this.cache.shouldRebuild(this.projectConfig.buildTool, this.projectService)) {
|
|
23
|
+
Logger.success("Build cache hit! Skipping full build.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
const command = [];
|
|
29
|
+
const env = { ...process.env };
|
|
13
30
|
|
|
14
31
|
if (this.projectConfig.buildTool === 'maven') {
|
|
15
32
|
command.push("mvn");
|
|
33
|
+
|
|
34
|
+
if (!this.cache.shouldRebuild('maven', this.projectService)) {
|
|
35
|
+
command.push("-o");
|
|
36
|
+
}
|
|
37
|
+
|
|
16
38
|
if (incremental) {
|
|
17
39
|
command.push("compile");
|
|
18
40
|
} else {
|
|
19
|
-
command.push("clean"
|
|
41
|
+
if (this.projectConfig.clean) command.push("clean");
|
|
42
|
+
command.push("compile", "war:exploded");
|
|
43
|
+
command.push("-T", "1C");
|
|
20
44
|
}
|
|
21
|
-
command.push("-
|
|
45
|
+
command.push("-Dmaven.test.skip=true", "-Dmaven.javadoc.skip=true");
|
|
22
46
|
if (this.projectConfig.profile) command.push(`-P${this.projectConfig.profile}`);
|
|
47
|
+
|
|
48
|
+
env.MAVEN_OPTS = "-Xms512m -Xmx1024m -XX:+UseParallelGC";
|
|
23
49
|
} else {
|
|
24
50
|
command.push("gradle");
|
|
25
51
|
if (incremental) {
|
|
26
52
|
command.push("classes");
|
|
27
53
|
} else {
|
|
28
|
-
command.push("clean"
|
|
54
|
+
if (this.projectConfig.clean) command.push("clean");
|
|
55
|
+
command.push("war");
|
|
56
|
+
command.push("--parallel", "--build-cache");
|
|
29
57
|
}
|
|
30
|
-
command.push("-x", "test");
|
|
58
|
+
command.push("-x", "test", "-x", "javadoc");
|
|
31
59
|
if (this.projectConfig.profile) command.push(`-Pprofile=${this.projectConfig.profile}`);
|
|
60
|
+
|
|
61
|
+
env.GRADLE_OPTS = "-Xmx1024m -Dorg.gradle.daemon=true";
|
|
32
62
|
}
|
|
33
63
|
|
|
34
64
|
const stopSpinner = (this.projectConfig.verbose) ? () => {} : Logger.spinner(incremental ? "Incremental compilation" : "Full project build");
|
|
35
65
|
|
|
36
66
|
const proc = Bun.spawn(command, {
|
|
37
67
|
stdout: "pipe",
|
|
38
|
-
stderr: "pipe"
|
|
68
|
+
stderr: "pipe",
|
|
69
|
+
env: env as any
|
|
39
70
|
});
|
|
40
71
|
|
|
41
72
|
if (this.projectConfig.verbose) {
|
|
42
73
|
await Promise.all([
|
|
43
|
-
this.processBuildLogs(proc.stdout, false),
|
|
44
|
-
this.processBuildLogs(proc.stderr, false)
|
|
74
|
+
this.processBuildLogs(proc.stdout as ReadableStream, false),
|
|
75
|
+
this.processBuildLogs(proc.stderr as ReadableStream, false)
|
|
45
76
|
]);
|
|
46
77
|
}
|
|
47
78
|
|
|
@@ -56,6 +87,10 @@ export class BuildService {
|
|
|
56
87
|
Logger.error(`${this.projectConfig.buildTool.toUpperCase()} build failed!`);
|
|
57
88
|
throw new Error("Falha no build do Java!");
|
|
58
89
|
}
|
|
90
|
+
|
|
91
|
+
if (!incremental) {
|
|
92
|
+
this.cache.saveCache(this.projectConfig.buildTool);
|
|
93
|
+
}
|
|
59
94
|
}
|
|
60
95
|
|
|
61
96
|
private async processBuildLogs(stream: ReadableStream, quiet: boolean) {
|
|
@@ -97,98 +132,86 @@ export class BuildService {
|
|
|
97
132
|
}
|
|
98
133
|
}
|
|
99
134
|
|
|
100
|
-
async syncClasses(): Promise<string | null> {
|
|
101
|
-
const
|
|
102
|
-
let appFolder = this.projectConfig.appName || this.inferredAppName || "";
|
|
103
|
-
|
|
135
|
+
async syncClasses(customSrc?: string): Promise<string | null> {
|
|
136
|
+
const appFolder = this.projectService.getInferredAppName();
|
|
104
137
|
const webappsPath = path.join(this.tomcatConfig.path, this.tomcatConfig.webapps);
|
|
105
138
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
.filter((dirent: any) => dirent.isDirectory() && !["ROOT", "manager", "host-manager", "docs", "examples"].includes(dirent.name));
|
|
109
|
-
|
|
110
|
-
if (folders.length === 1) {
|
|
111
|
-
appFolder = folders[0].name;
|
|
112
|
-
} else if (folders.length > 1) {
|
|
113
|
-
const sorted = folders.map((f: any) => ({
|
|
114
|
-
name: f.name,
|
|
115
|
-
time: fs.statSync(path.join(webappsPath, f.name)).mtimeMs
|
|
116
|
-
})).sort((a: any, b: any) => b.time - a.time);
|
|
117
|
-
appFolder = sorted[0].name;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const sourceDir = this.projectConfig.buildTool === 'maven' ? 'target/classes' : 'build/classes/java/main';
|
|
122
|
-
const destDir = path.join(webappsPath, appFolder, "WEB-INF", "classes");
|
|
139
|
+
const sourceDir = customSrc || this.projectService.getClassesDir();
|
|
140
|
+
const destDir = customSrc ? path.join(webappsPath, appFolder) : path.join(webappsPath, appFolder, "WEB-INF", "classes");
|
|
123
141
|
|
|
124
|
-
if (!
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
142
|
+
if (!existsSync(sourceDir)) return null;
|
|
143
|
+
if (!appFolder || !existsSync(destDir)) {
|
|
144
|
+
if (customSrc && appFolder) {
|
|
145
|
+
mkdirSync(destDir, { recursive: true });
|
|
146
|
+
} else {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
128
149
|
}
|
|
129
150
|
|
|
130
|
-
const
|
|
131
|
-
if (!
|
|
132
|
-
const list = fs.
|
|
133
|
-
|
|
151
|
+
const fastSync = async (src: string, dest: string) => {
|
|
152
|
+
if (!existsSync(dest)) await fs.mkdir(dest, { recursive: true });
|
|
153
|
+
const list = await fs.readdir(src, { withFileTypes: true });
|
|
154
|
+
|
|
155
|
+
const tasks = list.map(async (item) => {
|
|
134
156
|
const s = path.join(src, item.name);
|
|
135
157
|
const d = path.join(dest, item.name);
|
|
158
|
+
|
|
136
159
|
if (item.isDirectory()) {
|
|
137
|
-
|
|
160
|
+
await fastSync(s, d);
|
|
138
161
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
162
|
+
const sStat = await fs.stat(s);
|
|
163
|
+
let shouldCopy = false;
|
|
164
|
+
|
|
165
|
+
if (!existsSync(d)) {
|
|
166
|
+
shouldCopy = true;
|
|
167
|
+
} else {
|
|
168
|
+
const dStat = await fs.stat(d);
|
|
169
|
+
if (sStat.mtimeMs > dStat.mtimeMs || dStat.size === 0) {
|
|
170
|
+
shouldCopy = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (shouldCopy) {
|
|
175
|
+
let retries = 3;
|
|
176
|
+
while (retries > 0) {
|
|
177
|
+
try {
|
|
178
|
+
await fs.copyFile(s, d);
|
|
179
|
+
const finalStat = await fs.stat(d);
|
|
180
|
+
if (item.name.endsWith(".jar") && finalStat.size === 0 && sStat.size > 0) {
|
|
181
|
+
throw new Error("Zero byte copy detected");
|
|
182
|
+
}
|
|
183
|
+
await fs.utimes(d, sStat.atime, sStat.mtime);
|
|
184
|
+
break;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
retries--;
|
|
187
|
+
if (retries === 0) {
|
|
188
|
+
Logger.warn(`Failed to copy ${item.name} after retries.`);
|
|
189
|
+
} else {
|
|
190
|
+
await new Promise(r => setTimeout(r, 100));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
141
194
|
}
|
|
142
195
|
}
|
|
143
|
-
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await Promise.all(tasks);
|
|
144
199
|
};
|
|
145
200
|
|
|
146
|
-
|
|
201
|
+
await fastSync(sourceDir, destDir);
|
|
147
202
|
return appFolder;
|
|
148
203
|
}
|
|
149
204
|
|
|
150
|
-
async deployToWebapps(): Promise<{ path: string, finalName: string }> {
|
|
151
|
-
const destDir = path.join(this.tomcatConfig.path, this.tomcatConfig.webapps);
|
|
152
|
-
|
|
205
|
+
async deployToWebapps(): Promise<{ path: string, finalName: string, isDirectory: boolean }> {
|
|
153
206
|
Logger.step("Searching for generated artifacts");
|
|
154
207
|
|
|
155
|
-
const
|
|
156
|
-
let results: string[] = [];
|
|
157
|
-
const list = readdirSync(dir, { withFileTypes: true });
|
|
158
|
-
for (const item of list) {
|
|
159
|
-
const res = path.resolve(dir, item.name);
|
|
160
|
-
if (item.isDirectory()) {
|
|
161
|
-
if (item.name === 'target' || item.name === 'build') {
|
|
162
|
-
results = results.concat(findWars(res));
|
|
163
|
-
} else if (!['node_modules', '.git', 'src', 'webapps', 'bin', 'conf', 'lib', 'logs', 'temp', 'work'].includes(item.name)) {
|
|
164
|
-
results = results.concat(findWars(res));
|
|
165
|
-
}
|
|
166
|
-
} else if (item.name.endsWith('.war')) {
|
|
167
|
-
results.push(res);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return results;
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
const allWars = findWars(process.cwd())
|
|
174
|
-
.map(f => ({ path: f, name: path.basename(f), time: statSync(f).mtime.getTime() }))
|
|
175
|
-
.sort((a, b) => b.time - a.time);
|
|
176
|
-
|
|
177
|
-
if (allWars.length === 0) {
|
|
178
|
-
throw new Error('Nenhum arquivo .war encontrado! Verifique se o build realmente gerou um artefato.');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const warFile = allWars[0];
|
|
182
|
-
const finalName = this.projectConfig.appName ? `${this.projectConfig.appName}.war` : warFile.name;
|
|
208
|
+
const artifact = this.projectService.getArtifact();
|
|
183
209
|
|
|
184
210
|
if (!this.projectConfig.quiet) {
|
|
185
|
-
Logger.info("Artifact",
|
|
186
|
-
if (this.projectConfig.appName) Logger.info("Deploy as",
|
|
187
|
-
} else {
|
|
188
|
-
Logger.process(`Deploying ${this.projectConfig.appName ? this.projectConfig.appName : warFile.name.replace(".war", "")}...`);
|
|
211
|
+
Logger.info(artifact.isDirectory ? "Exploded Dir" : "Artifact", path.basename(artifact.path));
|
|
212
|
+
if (this.projectConfig.appName) Logger.info("Deploy as", artifact.name);
|
|
189
213
|
}
|
|
190
214
|
|
|
191
|
-
|
|
192
|
-
return { path: warFile.path, finalName };
|
|
215
|
+
return { path: artifact.path, finalName: artifact.name, isDirectory: artifact.isDirectory };
|
|
193
216
|
}
|
|
194
217
|
}
|
|
@@ -18,6 +18,23 @@ export class EndpointService {
|
|
|
18
18
|
const content = readFileSync(res, 'utf8');
|
|
19
19
|
const fileEndpoints = this.parseJavaFile(content, item.name, contextPath);
|
|
20
20
|
endpoints.push(...fileEndpoints);
|
|
21
|
+
} else if (item.name.endsWith('.jsp')) {
|
|
22
|
+
const parts = res.split(/[/\\]/);
|
|
23
|
+
const webappIndex = parts.indexOf("webapp");
|
|
24
|
+
const webContentIndex = parts.indexOf("WebContent");
|
|
25
|
+
const rootIndex = webappIndex !== -1 ? webappIndex : webContentIndex;
|
|
26
|
+
|
|
27
|
+
if (rootIndex !== -1) {
|
|
28
|
+
const relPath = "/" + parts.slice(rootIndex + 1).join("/");
|
|
29
|
+
endpoints.push({
|
|
30
|
+
method: "GET",
|
|
31
|
+
path: relPath,
|
|
32
|
+
fullPath: this.combinePaths(contextPath, relPath),
|
|
33
|
+
className: "JSP",
|
|
34
|
+
methodName: item.name,
|
|
35
|
+
parameters: []
|
|
36
|
+
});
|
|
37
|
+
}
|
|
21
38
|
}
|
|
22
39
|
}
|
|
23
40
|
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import type { ProjectConfig } from "../types/config";
|
|
4
|
+
|
|
5
|
+
export class ProjectService {
|
|
6
|
+
constructor(private config: ProjectConfig) {}
|
|
7
|
+
|
|
8
|
+
getBuildOutputDir(): string {
|
|
9
|
+
return path.join(process.cwd(), this.config.buildTool === "maven" ? "target" : "build");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getClassesDir(): string {
|
|
13
|
+
return this.config.buildTool === "maven"
|
|
14
|
+
? path.join(process.cwd(), "target", "classes")
|
|
15
|
+
: path.join(process.cwd(), "build", "classes", "java", "main");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getSourceDirs(): string[] {
|
|
19
|
+
return [
|
|
20
|
+
path.join(process.cwd(), "src", "main", "java"),
|
|
21
|
+
path.join(process.cwd(), "src", "main", "resources"),
|
|
22
|
+
path.join(process.cwd(), "src", "main", "webapp")
|
|
23
|
+
].filter(d => existsSync(d));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getArtifact(): { path: string; name: string; isDirectory: boolean } {
|
|
27
|
+
const buildDir = this.getBuildOutputDir();
|
|
28
|
+
const artifacts = this.searchArtifacts(buildDir).sort((a, b) => b.time - a.time);
|
|
29
|
+
|
|
30
|
+
if (artifacts.length === 0) {
|
|
31
|
+
throw new Error(`Nenhum artefato (.war ou pasta exploded) encontrado em ${buildDir}!`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const artifact = artifacts[0];
|
|
35
|
+
return {
|
|
36
|
+
path: artifact.path,
|
|
37
|
+
name: this.config.appName ? `${this.config.appName}.war` : artifact.name,
|
|
38
|
+
isDirectory: artifact.isDirectory
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private searchArtifacts(dir: string): { path: string; name: string; time: number; isDirectory: boolean }[] {
|
|
43
|
+
let results: { path: string; name: string; time: number; isDirectory: boolean }[] = [];
|
|
44
|
+
if (!existsSync(dir)) return results;
|
|
45
|
+
|
|
46
|
+
const list = readdirSync(dir, { withFileTypes: true });
|
|
47
|
+
for (const item of list) {
|
|
48
|
+
const fullPath = path.resolve(dir, item.name);
|
|
49
|
+
|
|
50
|
+
if (item.isDirectory()) {
|
|
51
|
+
// Se for Maven e tiver WEB-INF, é um exploded war
|
|
52
|
+
if (this.config.buildTool === 'maven' && existsSync(path.join(fullPath, "WEB-INF"))) {
|
|
53
|
+
results.push({
|
|
54
|
+
path: fullPath,
|
|
55
|
+
name: `${item.name}.war`,
|
|
56
|
+
time: statSync(fullPath).mtime.getTime(),
|
|
57
|
+
isDirectory: true
|
|
58
|
+
});
|
|
59
|
+
} else if (item.name.endsWith('.war')) { // Algumas ferramentas podem gerar pastas .war
|
|
60
|
+
results.push({
|
|
61
|
+
path: fullPath,
|
|
62
|
+
name: item.name,
|
|
63
|
+
time: statSync(fullPath).mtime.getTime(),
|
|
64
|
+
isDirectory: true
|
|
65
|
+
});
|
|
66
|
+
} else if (['libs', 'distributions'].includes(item.name)) { // Gradle common dirs
|
|
67
|
+
results = results.concat(this.searchArtifacts(fullPath));
|
|
68
|
+
}
|
|
69
|
+
} else if (item.name.endsWith('.war')) {
|
|
70
|
+
results.push({
|
|
71
|
+
path: fullPath,
|
|
72
|
+
name: item.name,
|
|
73
|
+
time: statSync(fullPath).mtime.getTime(),
|
|
74
|
+
isDirectory: false
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return results;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getInferredAppName(): string {
|
|
82
|
+
if (this.config.appName) return this.config.appName;
|
|
83
|
+
try {
|
|
84
|
+
const artifact = this.getArtifact();
|
|
85
|
+
return artifact.name.replace(".war", "");
|
|
86
|
+
} catch (e) {
|
|
87
|
+
return "ROOT";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
findAllClassPaths(): string[] {
|
|
92
|
+
const results: string[] = [];
|
|
93
|
+
const root = process.cwd();
|
|
94
|
+
|
|
95
|
+
const scan = (dir: string) => {
|
|
96
|
+
try {
|
|
97
|
+
const files = readdirSync(dir, { withFileTypes: true });
|
|
98
|
+
for (const file of files) {
|
|
99
|
+
if (!file.isDirectory()) continue;
|
|
100
|
+
|
|
101
|
+
const name = file.name;
|
|
102
|
+
if (name.startsWith('.') || ['node_modules', 'out', 'bin', 'src', 'webapps', '.xavva'].includes(name)) continue;
|
|
103
|
+
|
|
104
|
+
const fullPath = path.join(dir, name);
|
|
105
|
+
|
|
106
|
+
const isMavenClasses = this.config.buildTool === 'maven' && name === 'classes' && dir.endsWith('target');
|
|
107
|
+
const isGradleClasses = this.config.buildTool === 'gradle' && name === 'main' && dir.endsWith(path.join('classes', 'java'));
|
|
108
|
+
|
|
109
|
+
if (isMavenClasses || isGradleClasses) {
|
|
110
|
+
results.push(fullPath.replace(/\\/g, "/"));
|
|
111
|
+
} else {
|
|
112
|
+
scan(fullPath);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch (e) {}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
scan(root);
|
|
119
|
+
|
|
120
|
+
if (results.length === 0) {
|
|
121
|
+
results.push(this.getClassesDir().replace(/\\/g, "/"));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return results;
|
|
125
|
+
}
|
|
126
|
+
}
|