Skip to content

Commit

Permalink
Merge pull request #1548 from tgodzik/fix-zgc
Browse files Browse the repository at this point in the history
bugfix: Fix issues when zgc is not fully supported
  • Loading branch information
tgodzik authored Oct 28, 2024
2 parents 2db44b4 + de7c8ae commit 17ff8e7
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe("getJavaHome", () => {
new MockOutput()
);
jest.restoreAllMocks();
expect(javaHome).toBe(JAVA_HOME);
expect(javaHome.path).toBe(JAVA_HOME);
});

// needs to run on a machine with an actual JAVA_HOME set up
Expand Down Expand Up @@ -90,7 +90,7 @@ describe("getJavaHome", () => {
new MockOutput()
);
jest.restoreAllMocks();
expect(javaHome).toBe(pathJavaHome);
expect(javaHome.path).toBe(pathJavaHome);
});
});

Expand Down
7 changes: 5 additions & 2 deletions packages/metals-languageclient/src/getJavaConfig.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { JavaHome } from "./getJavaHome";
import { getJavaOptions } from "./getJavaOptions";
import * as path from "path";

export interface JavaConfig {
javaOptions: string[];
javaPath: string;
javaHome: JavaHome;
coursier: string;
coursierMirrorFilePath: string | undefined;
extraEnv: {
Expand All @@ -13,7 +15,7 @@ export interface JavaConfig {

interface GetJavaConfigOptions {
workspaceRoot: string | undefined;
javaHome: string;
javaHome: JavaHome;
coursier: string;
coursierMirrorFilePath: string | undefined;
customRepositories: string[] | undefined;
Expand All @@ -27,7 +29,7 @@ export function getJavaConfig({
customRepositories = [],
}: GetJavaConfigOptions): JavaConfig {
const javaOptions = getJavaOptions(workspaceRoot);
const javaPath = path.join(javaHome, "bin", "java");
const javaPath = path.join(javaHome.path, "bin", "java");

const coursierRepositories =
customRepositories.length > 0
Expand All @@ -45,6 +47,7 @@ export function getJavaConfig({
return {
javaOptions,
javaPath,
javaHome,
coursier,
coursierMirrorFilePath,
extraEnv,
Expand Down
51 changes: 35 additions & 16 deletions packages/metals-languageclient/src/getJavaHome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { realpathSync } from "fs";

export type JavaVersion = "11" | "17" | "21";

export interface JavaHome {
path: string;
description: string;
version: string;
}

/**
* Computes the user's Java Home path, using various strategies:
*
Expand All @@ -19,17 +25,17 @@ export type JavaVersion = "11" | "17" | "21";
export async function getJavaHome(
javaVersion: JavaVersion,
outputChannel: OutputChannel
): Promise<string | undefined> {
): Promise<JavaHome | undefined> {
const fromEnvValue = await fromEnv(javaVersion, outputChannel);
return fromEnvValue || (await fromPath(javaVersion, outputChannel));
}

const versionRegex = /\"\d\d/;
async function validateJavaVersion(
export async function validateJavaVersion(
javaHome: string,
javaVersion: JavaVersion,
outputChannel: OutputChannel
): Promise<boolean> {
): Promise<JavaHome | undefined> {
const javaBin = path.join(javaHome, "bin", "java");
try {
const javaVersionOut = spawn(javaBin, ["-version"], {
Expand All @@ -43,14 +49,18 @@ async function validateJavaVersion(

const javaInfoStr = (await javaVersionOut).stderr as string;
const matches = javaInfoStr.match(versionRegex);
if (matches) {
return +matches[0].slice(1, 3) >= +javaVersion;
if (matches && +matches[0].slice(1, 3) >= +javaVersion) {
return {
path: javaHome,
description: javaInfoStr,
version: matches[0].slice(1, 3),
};
}
} catch (error) {
outputChannel.appendLine(`failed while running ${javaBin} -version`);
outputChannel.appendLine(`${error}`);
}
return false;
return undefined;
}

function propertyValueOf(
Expand All @@ -70,7 +80,7 @@ function propertyValueOf(
export async function fromPath(
javaVersion: JavaVersion,
outputChannel: OutputChannel
): Promise<string | undefined> {
): Promise<JavaHome | undefined> {
let javaExecutable = findOnPath(["java"]);
if (javaExecutable) {
const realJavaPath = realpathSync(javaExecutable);
Expand All @@ -86,13 +96,22 @@ export async function fromPath(
cmdOutput,
"java.specification.version"
);
const isValid =
discoveredJavaHome &&
discoveredJavaVersion &&
parseInt(discoveredJavaVersion) >= parseInt(javaVersion);
function getLastThreeLines(text: string): string {
let lines = text.split(/\r?\n/);
return lines.slice(-3).join("\n");
}

if (isValid) return discoveredJavaHome;
else {
if (
discoveredJavaVersion &&
discoveredJavaHome &&
parseInt(discoveredJavaVersion) >= parseInt(javaVersion)
) {
return {
path: discoveredJavaHome,
description: getLastThreeLines(cmdOutput),
version: discoveredJavaVersion,
};
} else {
outputChannel.appendLine(
`Java version doesn't match the required one of ${javaVersion}`
);
Expand All @@ -109,18 +128,18 @@ export async function fromPath(
export async function fromEnv(
javaVersion: JavaVersion,
outputChannel: OutputChannel
): Promise<string | undefined> {
): Promise<JavaHome | undefined> {
const javaHome = process.env["JAVA_HOME"];
if (javaHome) {
outputChannel.appendLine(
`Checking Java in JAVA_HOME, which points to ${javaHome}`
);
const isValid = await validateJavaVersion(
const validatedJavaHome = await validateJavaVersion(
javaHome,
javaVersion,
outputChannel
);
if (isValid) return javaHome;
if (validatedJavaHome) return validatedJavaHome;
else {
outputChannel.appendLine(
`Java version doesn't match the required one of ${javaVersion}`
Expand Down
50 changes: 32 additions & 18 deletions packages/metals-languageclient/src/getServerOptions.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,53 @@
import { ServerOptions } from "./interfaces/ServerOptions";
import { JavaConfig } from "./getJavaConfig";

interface GetServerOptions {
metalsClasspath: string;
serverProperties: string[] | undefined;
clientName?: string;
javaConfig: JavaConfig;
}

export function getServerOptions({
metalsClasspath,
serverProperties = [],
clientName,
javaConfig: { javaOptions, javaPath, extraEnv },
}: GetServerOptions): ServerOptions {
export function getServerOptions(
metalsClasspath: string,
serverProperties: string[],
clientName: string,
javaConfig: JavaConfig
): ServerOptions {
const baseProperties = ["-Xss4m", "-Xms100m"];

if (clientName) {
baseProperties.push(`-Dmetals.client=${clientName}`);
}

/**
* GraalVM for JDK 17-20 prints additional warnings that breaks things
*/
const skipZGC =
+javaConfig.javaHome.version < 21 &&
javaConfig.javaHome.description.indexOf("GraalVM") > -1;

var filteredServerProperties = serverProperties;
if (skipZGC) {
filteredServerProperties = serverProperties.filter(function (prop) {
return prop.indexOf("UseZGC") === -1;
});
}
const mainArgs = ["-classpath", metalsClasspath, "scala.meta.metals.Main"];

// let user properties override base properties
const launchArgs = [
...baseProperties,
...javaOptions,
...serverProperties,
...javaConfig.javaOptions,
...filteredServerProperties,
...mainArgs,
];

const env = () => ({ ...process.env, ...extraEnv });
const env = () => ({ ...process.env, ...javaConfig.extraEnv });

return {
run: { command: javaPath, args: launchArgs, options: { env: env() } },
debug: { command: javaPath, args: launchArgs, options: { env: env() } },
run: {
command: javaConfig.javaPath,
args: launchArgs,
options: { env: env() },
},
debug: {
command: javaConfig.javaPath,
args: launchArgs,
options: { env: env() },
},
};
}
21 changes: 17 additions & 4 deletions packages/metals-languageclient/src/setupCoursier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import {
PromisifySpawnOptions,
spawn,
} from "promisify-child-process";
import { JavaVersion, getJavaHome } from "./getJavaHome";
import {
JavaHome,
JavaVersion,
getJavaHome,
validateJavaVersion,
} from "./getJavaHome";
import { OutputChannel } from "./interfaces/OutputChannel";
import path from "path";
import fs from "fs";
Expand All @@ -23,7 +28,7 @@ export async function setupCoursier(
output: OutputChannel,
forceCoursierJar: boolean,
serverProperties: string[]
): Promise<{ coursier: string; javaHome: string }> {
): Promise<{ coursier: string; javaHome: JavaHome }> {
const handleOutput = (out: Buffer) => {
const msg = "\t" + out.toString().trim().split("\n").join("\n\t");
output.appendLine(msg);
Expand Down Expand Up @@ -107,10 +112,18 @@ export async function setupCoursier(
output.appendLine(
`No installed java with version ${javaVersion} found. Will fetch one using coursier:`
);
javaHome = await resolveJavaHomeWithCoursier(coursier);
const coursierJavaHome = await resolveJavaHomeWithCoursier(coursier);
const validatedJavaHome = await validateJavaVersion(
coursierJavaHome,
javaVersion,
output
);
if (validatedJavaHome) {
javaHome = validatedJavaHome;
}
}

output.appendLine(`Using Java Home: ${javaHome}`);
output.appendLine(`Using Java Home: ${javaHome?.path}`);

/* If we couldn't download coursier, but we have Java
* we can still fall back to jar based launcher.
Expand Down
8 changes: 4 additions & 4 deletions packages/metals-vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,12 @@ function launchMetals(
// Make editing Scala docstrings slightly nicer.
enableScaladocIndentation();

const serverOptions = getServerOptions({
const serverOptions = getServerOptions(
metalsClasspath,
serverProperties,
javaConfig,
clientName: "vscode",
});
"vscode",
javaConfig
);

const initializationOptions: MetalsInitializationOptions = {
compilerOptions: {
Expand Down

0 comments on commit 17ff8e7

Please sign in to comment.