Skip to content

Commit d17e9db

Browse files
fix: parse java output correctly
1 parent e1024d7 commit d17e9db

File tree

3 files changed

+90
-20
lines changed

3 files changed

+90
-20
lines changed

lib/sys-info.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Constants } from "./constants";
1313

1414
export class SysInfo implements NativeScriptDoctor.ISysInfo {
1515
private static JAVA_COMPILER_VERSION_REGEXP = /^javac (.*)/im;
16+
private static JAVA_VERSION_REGEXP = /^(?:(?:java)|(?:openjdk)).*?\"(.*)\"/im;
1617
private static XCODE_VERSION_REGEXP = /Xcode (.*)/;
1718
private static VERSION_REGEXP = /(\d{1,})\.(\d{1,})\.*([\w-]{0,})/m;
1819
private static CLI_OUTPUT_VERSION_REGEXP = /^(?:\d+\.){2}\d+.*?$/m;
@@ -60,27 +61,29 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
6061

6162
public getJavaCompilerVersion(): Promise<string> {
6263
return this.getValueForProperty(() => this.javaCompilerVerCache, async (): Promise<string> => {
63-
const javacVersion = (await this.getJavacVersionFromJavaHome()) || (await this.getJavacVersionFromPath());
64+
const javacVersion = (await this.getVersionOfJavaExecutableFromJavaHome(Constants.JAVAC_EXECUTABLE_NAME, SysInfo.JAVA_COMPILER_VERSION_REGEXP)) ||
65+
(await this.getVersionOfJavaExecutableFromPath(Constants.JAVAC_EXECUTABLE_NAME, SysInfo.JAVA_COMPILER_VERSION_REGEXP));
66+
6467
return javacVersion;
6568
});
6669
}
6770

6871
public getJavaVersion(): Promise<string> {
6972
return this.getValueForProperty(() => this.javaVerCache, async (): Promise<string> => {
70-
const javacVersion = (await this.getJavaVersionFromJavaHome()) || (await this.getJavaVersionFromPath());
71-
return javacVersion;
73+
const javaVersion = (await this.getJavaVersionFromJavaHome()) || (await this.getJavaVersionFromPath());
74+
return javaVersion;
7275
});
7376
}
7477

7578
public getJavaVersionFromPath(): Promise<string> {
7679
return this.getValueForProperty(() => this.javaVerPathCache, (): Promise<string> => {
77-
return this.getVersionOfJavaExecutableFromPath(Constants.JAVA_EXECUTABLE_NAME);
80+
return this.getVersionOfJavaExecutableFromPath(Constants.JAVA_EXECUTABLE_NAME, SysInfo.JAVA_VERSION_REGEXP);
7881
});
7982
}
8083

8184
public getJavaVersionFromJavaHome(): Promise<string> {
8285
return this.getValueForProperty(() => this.javaVerJavaHomeCache, (): Promise<string> => {
83-
return this.getVersionOfJavaExecutableFromJavaHome(Constants.JAVA_EXECUTABLE_NAME);
86+
return this.getVersionOfJavaExecutableFromJavaHome(Constants.JAVA_EXECUTABLE_NAME, SysInfo.JAVA_VERSION_REGEXP);
8487
});
8588
}
8689

@@ -505,6 +508,7 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
505508

506509
result.dotNetVer = await this.hostInfo.dotNetVersion();
507510
result.javacVersion = await this.getJavaCompilerVersion();
511+
result.javaVersion = await this.getJavaVersion();
508512
result.adbVer = await this.getAdbVersion(config && config.androidToolsInfo && config.androidToolsInfo.pathToAdb);
509513
result.androidInstalled = await this.isAndroidInstalled();
510514
result.monoVer = await this.getMonoVersion();
@@ -515,15 +519,7 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
515519
});
516520
}
517521

518-
private async getJavacVersionFromPath(): Promise<string> {
519-
return this.getVersionOfJavaExecutableFromPath(Constants.JAVAC_EXECUTABLE_NAME);
520-
}
521-
522-
private getJavacVersionFromJavaHome(): Promise<string> {
523-
return this.getVersionOfJavaExecutableFromJavaHome(Constants.JAVAC_EXECUTABLE_NAME);
524-
}
525-
526-
private async getVersionOfJavaExecutableFromJavaHome(javaExecutableName: string): Promise<string> {
522+
private async getVersionOfJavaExecutableFromJavaHome(javaExecutableName: string, regExp: RegExp): Promise<string> {
527523
let javaExecutableVersion: string = null;
528524

529525
try {
@@ -533,31 +529,31 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
533529
if (javaHome) {
534530
const pathToJavaExecutable = path.join(javaHome, "bin", javaExecutableFile);
535531
if (this.fileSystem.exists(pathToJavaExecutable)) {
536-
javaExecutableVersion = await this.getVersionOfJavaExecutable(pathToJavaExecutable);
532+
javaExecutableVersion = await this.getVersionOfJavaExecutable(pathToJavaExecutable, regExp);
537533
}
538534
}
539535
} catch (err) { /* intentionally left blank */ }
540536

541537
return javaExecutableVersion;
542538
}
543539

544-
private async getVersionOfJavaExecutableFromPath(javaExecutableName: string): Promise<string> {
540+
private async getVersionOfJavaExecutableFromPath(javaExecutableName: string, regExp: RegExp): Promise<string> {
545541
let javaExecutableVersion: string = null;
546542

547543
try {
548544
const detectionCommand = this.hostInfo.isWindows ? "where" : "which";
549545
// if this command succeeds, we have javac in the PATH. In case it is not there, it will throw an error.
550546
await this.childProcess.exec(`${detectionCommand} ${javaExecutableName}`);
551-
javaExecutableVersion = await this.getVersionOfJavaExecutable(javaExecutableName);
547+
javaExecutableVersion = await this.getVersionOfJavaExecutable(javaExecutableName, regExp);
552548
} catch (err) { /* intentionally left blank */ }
553549

554550
return javaExecutableVersion;
555551
}
556552

557-
private async getVersionOfJavaExecutable(pathToExecutable: string): Promise<string> {
553+
private async getVersionOfJavaExecutable(executable: string, regExp: RegExp): Promise<string> {
558554
try {
559-
const output = await this.childProcess.exec(`"${pathToExecutable}" -version`);
560-
return SysInfo.JAVA_COMPILER_VERSION_REGEXP.exec(`${output.stderr}${EOL}${output.stdout}`)[1];
555+
const output = await this.childProcess.exec(`"${executable}" -version`);
556+
return regExp.exec(`${output.stderr}${EOL}${output.stdout}`)[1];
561557
} catch (err) {
562558
return null;
563559
}

test/sys-info.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ interface IChildProcessResults {
3131
npmV: IChildProcessResultDescription;
3232
nodeV: IChildProcessResultDescription;
3333
javacVersion: IChildProcessResultDescription;
34+
javaVersion: IChildProcessResultDescription;
3435
nodeGypVersion: IChildProcessResultDescription;
3536
xCodeVersion: IChildProcessResultDescription;
3637
adbVersion: IChildProcessResultDescription;
@@ -82,8 +83,11 @@ function createChildProcessResults(childProcessResult: IChildProcessResults): ID
8283
"npm -v": childProcessResult.npmV,
8384
"node -v": childProcessResult.nodeV,
8485
'"javac" -version': childProcessResult.javacVersion,
86+
'"java" -version': childProcessResult.javaVersion,
8587
'which javac': { result: '' },
8688
'where javac': { result: '' },
89+
'which java': { result: '' },
90+
'where java': { result: '' },
8791
"node-gyp -v": childProcessResult.nodeGypVersion,
8892
"xcodebuild -version": childProcessResult.xCodeVersion,
8993
"pod --version": childProcessResult.podVersion,
@@ -246,6 +250,38 @@ describe("SysInfo unit tests", () => {
246250
process.env[JavaHomeName] = originalJavaHome;
247251
assert.deepEqual(execCommands, ['where javac', '"javac" -version']);
248252
});
253+
254+
it("java version when there is JAVA_HOME.", async () => {
255+
const originalJavaHome = process.env[JavaHomeName];
256+
process.env[JavaHomeName] = "mock";
257+
258+
const pathToJava = path.join(process.env[JavaHomeName], "bin", "java");
259+
fileSystem.exists = () => true;
260+
await sysInfo.getJavaVersion();
261+
262+
process.env[JavaHomeName] = originalJavaHome;
263+
assert.deepEqual(execCommands[0], `"${pathToJava}" -version`);
264+
});
265+
266+
it("java version when there is no JAVA_HOME on non-Windows OS", async () => {
267+
const originalJavaHome = process.env[JavaHomeName];
268+
269+
delete process.env[JavaHomeName];
270+
await sysInfo.getJavaVersion();
271+
272+
process.env[JavaHomeName] = originalJavaHome;
273+
assert.deepEqual(execCommands, ['which java', '"java" -version']);
274+
});
275+
276+
it("java version when there is no JAVA_HOME on Window OS", async () => {
277+
const originalJavaHome = process.env[JavaHomeName];
278+
hostInfo.isWindows = true;
279+
delete process.env[JavaHomeName];
280+
await sysInfo.getJavaVersion();
281+
282+
process.env[JavaHomeName] = originalJavaHome;
283+
assert.deepEqual(execCommands, ['where java', '"java" -version']);
284+
});
249285
});
250286

251287
describe("getSysInfo", () => {
@@ -259,6 +295,11 @@ describe("SysInfo unit tests", () => {
259295
npmV: { result: setStdOut("2.14.1") },
260296
nodeV: { result: setStdOut("v6.0.0") },
261297
javacVersion: { result: setStdErr("javac 1.8.0_60") },
298+
javaVersion: {
299+
result: setStdErr(`java version "1.8.0_202"
300+
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
301+
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)`)
302+
},
262303
nodeGypVersion: { result: setStdOut("2.0.0") },
263304
xCodeVersion: { result: setStdOut("Xcode 6.4.0") },
264305
adbVersion: { result: setStdOut("Android Debug Bridge version 1.0.32") },
@@ -286,6 +327,7 @@ describe("SysInfo unit tests", () => {
286327
assert.deepEqual(result.npmVer, childProcessResult.npmV.result.stdout);
287328
assert.deepEqual(result.nodeVer, "6.0.0");
288329
assert.deepEqual(result.javacVersion, "1.8.0_60");
330+
assert.deepEqual(result.javaVersion, "1.8.0_202");
289331
assert.deepEqual(result.nodeGypVer, childProcessResult.nodeGypVersion.result.stdout);
290332
assert.deepEqual(result.adbVer, "1.0.32");
291333
assert.deepEqual(result.androidInstalled, true);
@@ -477,6 +519,7 @@ ${expectedCliVersion}`;
477519
npmV: { shouldThrowError: true },
478520
nodeV: { shouldThrowError: true },
479521
javacVersion: { shouldThrowError: true },
522+
javaVersion: { shouldThrowError: true },
480523
nodeGypVersion: { shouldThrowError: true },
481524
xCodeVersion: { shouldThrowError: true },
482525
adbVersion: { shouldThrowError: true },
@@ -594,5 +637,31 @@ ${expectedCliVersion}`;
594637
assertiOSSysInfo(result);
595638
});
596639
});
640+
641+
describe("getJavaVersion", () => {
642+
it("parses correctly OpenJDK output", async () => {
643+
childProcessResult.javaVersion = {
644+
result: setStdOut(`openjdk version "1.8.0_64"
645+
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_64-b08)
646+
OpenJDK 64-Bit Server VM (build 25.202-b08, mixed mode)`)
647+
};
648+
649+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: true, dotNetVersion });
650+
const result = await sysInfo.getJavaVersion();
651+
assert.equal(result, "1.8.0_64");
652+
});
653+
654+
it("parses correctly OpenJDK output", async () => {
655+
childProcessResult.javaVersion = {
656+
result: setStdOut(`java version "1.8.0_25"
657+
Java(TM) SE Runtime Environment (build 1.8.0_25-b08)
658+
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)`)
659+
};
660+
661+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: true, dotNetVersion });
662+
const result = await sysInfo.getJavaVersion();
663+
assert.equal(result, "1.8.0_25");
664+
});
665+
});
597666
});
598667
});

typings/interfaces.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,11 @@ declare module NativeScriptDoctor {
317317
* @type {string}
318318
*/
319319
javacVersion: string;
320+
/**
321+
* java version string as returned by `java -version`.
322+
* @type {string}
323+
*/
324+
javaVersion: string;
320325
/**
321326
* true if the Android SDK Tools are installed and configured correctly.
322327
* @type {boolean}

0 commit comments

Comments
 (0)