From a4532c4cf03854cae53da9873881382956da4298 Mon Sep 17 00:00:00 2001 From: Vadim Chelyshov Date: Fri, 14 Jan 2022 19:23:06 +0300 Subject: [PATCH] Fix javaHome selection for MacOs Should fix scalameta/metals-vscode#821 Instead of assuming that `java` should be a symlink to `java` in javaHome use the result of `locate-java-home` and select jdk that matches the `java` from $PATH. --- src/__tests__/getJavaHome.test.ts | 43 ++++++----------- src/getJavaHome.ts | 77 ++++++++++++++++--------------- 2 files changed, 54 insertions(+), 66 deletions(-) diff --git a/src/__tests__/getJavaHome.test.ts b/src/__tests__/getJavaHome.test.ts index e858c73..42881d5 100644 --- a/src/__tests__/getJavaHome.test.ts +++ b/src/__tests__/getJavaHome.test.ts @@ -31,31 +31,15 @@ describe("getJavaHome", () => { const javaPaths = [ { binPath: path.join("/", "test", "usr", "bin", "java"), - realPath: path.join( - "/", - "test", - "usr", - "lib", - "jvm", - "java-11-openjdk-amd64", - "bin", - "java" - ), + realPath: path.join(java8Jdk.path, "bin", "java"), }, ]; const PATH = path.join("/", "test", "usr", "bin"); + mockLocateJavaHome([java8Jdk, java11Jdk]); mockFs(javaPaths); process.env = { PATH }; - const javaHome = await getJavaHome(undefined); - const expected = path.join( - "/", - "test", - "usr", - "lib", - "jvm", - "java-11-openjdk-amd64" - ); - expect(javaHome).toBe(expected); + const javaHome = await require("../getJavaHome").getJavaHome(undefined); + expect(javaHome).toBe(java8Jdk.path); }); it("prefers configuration to JAVA_HOME and installed Java", async () => { @@ -105,42 +89,42 @@ describe("getJavaHome", () => { }); const java8Jdk = { - path: "/path/to/java8jdk", + path: path.join("/", "path", "to", "java8jdk"), version: "1.8.0", security: 1, isJDK: true, }; const java8Jre = { - path: "/path/to/java8jdk", + path: path.join("/", "path", "to", "java8jdk"), version: "1.8.0", security: 1, isJDK: false, }; const java11Jdk = { - path: "/path/to/java11jdk", + path: path.join("/", "path", "to", "java11jdk"), version: "1.11.0", security: 1, isJDK: true, }; const java17Jdk = { - path: "/path/to/java17jdk", + path: path.join("/", "path", "to", "java17jdk"), version: "1.17.0", security: 1, isJDK: true, }; const java11Jre = { - path: "/path/to/java11jdk", + path: path.join("/", "path", "to", "java11jdk"), version: "1.11.0", security: 1, isJDK: false, }; const java11JdkNewPatch = { - path: "/path/to/java11jdk/high/security", + path: path.join("/", "path", "to", "java11jdk", "high", "securiry"), version: "1.11.0", security: 192, isJDK: true, @@ -159,9 +143,9 @@ function mockLocateJavaHome( ...j, is64Bit: true, executables: { - java: j.path + "/bin/java", - javac: j.path + "/bin/javac", - javap: j.path + "/bin/javap", + java: path.join(j.path, "bin", "java"), + javac: path.join(j.path, "bin", "javac"), + javap: path.join(j.path, "bin", "javap"), }, })) ); @@ -169,7 +153,6 @@ function mockLocateJavaHome( } function mockFs(javaLinks: { binPath: String; realPath: String }[]): void { - jest.resetModules(); jest .spyOn(require("fs"), "existsSync") .mockImplementation((path: unknown) => { diff --git a/src/getJavaHome.ts b/src/getJavaHome.ts index 40f3aa0..300a4bf 100644 --- a/src/getJavaHome.ts +++ b/src/getJavaHome.ts @@ -28,12 +28,7 @@ export function getJavaHome( configuredJavaHome: string | undefined ): Promise { return toPromise( - pipe( - fromConfig(configuredJavaHome), - TE.orElse(fromEnv), - TE.orElse(fromPath), - TE.orElse(locate) - ) + pipe(fromConfig(configuredJavaHome), TE.orElse(fromEnv), TE.orElse(locate)) ); } @@ -55,30 +50,6 @@ function fromEnv(): TaskEither { return javaHome ? TE.right(javaHome) : TE.left({}); } -function fromPath(): TaskEither { - const value = process.env["PATH"]; - if (value) { - const result = value - .split(path.delimiter) - .map((p) => path.join(p, "java")) - .filter((p) => fs.existsSync(p)); - - if (result.length > 0) { - const realpath = fs.realpathSync(result[0]); - if (realpath.endsWith(path.join("bin", "java"))) { - const normalized = path.normalize(path.join(realpath, "..", "..")); - return TE.right(normalized); - } else { - return TE.left({}); - } - } else { - return TE.left({}); - } - } else { - return TE.left({}); - } -} - function locate(): TaskEither { return pipe( locateJavaHome({ version: ">=1.8 <=17" }), @@ -86,12 +57,9 @@ function locate(): TaskEither { if (!javaHomes || javaHomes.length === 0) { return TE.left(new Error("No suitable Java version found")); } else { - javaHomes.sort((a, b) => { - const byVersion = -semver.compare(a.version, b.version); - if (byVersion === 0) return b.security - a.security; - else return byVersion; - }); - const jdkHome = javaHomes.find((j) => j.isJDK); + const jdkHomes = javaHomes.filter((j) => j.isJDK); + const fromBinPath = matchesBinFromPath(jdkHomes); + const jdkHome = fromBinPath ? fromBinPath : latestJdk(jdkHomes); if (jdkHome) { return TE.right(jdkHome.path); } else { @@ -102,6 +70,43 @@ function locate(): TaskEither { ); } +function matchesBinFromPath( + jdkHomes: IJavaHomeInfo[] +): IJavaHomeInfo | undefined { + const value = process.env["PATH"]; + if (value && jdkHomes.length > 0) { + const result = value + .split(path.delimiter) + .map((p) => path.join(p, "java")) + .filter((p) => fs.existsSync(p)); + + if (result.length > 0) { + const realpath = fs.realpathSync(result[0]); + const matched = jdkHomes.find((home) => { + const javaBin = path.join(home.path, "bin", "java"); + return javaBin == realpath; + }); + return matched; + } else { + return undefined; + } + } else { + return undefined; + } +} + +function latestJdk(jdkHomes: IJavaHomeInfo[]): IJavaHomeInfo | undefined { + if (jdkHomes.length > 0) { + return jdkHomes.sort((a, b) => { + const byVersion = -semver.compare(a.version, b.version); + if (byVersion === 0) return b.security - a.security; + else return byVersion; + })[0]; + } else { + return undefined; + } +} + function locateJavaHome( opts: ILocateJavaHomeOptions ): TaskEither {