Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically register VMInstalls for the JDKs installed on the local machine #3251

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1545,7 +1545,7 @@
"fs-extra": "^8.1.0",
"glob": "^7.1.3",
"htmlparser2": "6.0.1",
"jdk-utils": "^0.4.4",
"jdk-utils": "^0.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"semver": "^7.5.2",
Expand Down
6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
initializationOptions: {
bundles: collectJavaExtensions(extensions.all),
workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null,
settings: { java: getJavaConfig(requirements.java_home) },
settings: { java: await getJavaConfig(requirements.java_home) },
extendedClientCapabilities: {
classFileContentsSupport: true,
overrideMethodsPromptSupport: true,
Expand Down Expand Up @@ -184,7 +184,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
didChangeConfiguration: async () => {
await standardClient.getClient().sendNotification(DidChangeConfigurationNotification.type, {
settings: {
java: getJavaConfig(requirements.java_home),
java: await getJavaConfig(requirements.java_home),
}
});
}
Expand Down Expand Up @@ -267,7 +267,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
// the promise is resolved
// no need to pass `resolve` into any code past this point,
// since `resolve` is a no-op from now on
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, getJavaConfig(requirements.java_home), context, true);
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, context, true);
if (requireSyntaxServer) {
if (process.env['SYNTAXLS_CLIENT_PORT']) {
syntaxClient.initialize(requirements, clientOptions);
Expand Down
9 changes: 6 additions & 3 deletions src/javaServerStarter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const HEAP_DUMP = '-XX:+HeapDumpOnOutOfMemoryError';
const DEPENDENCY_COLLECTOR_IMPL= '-Daether.dependencyCollector.impl=';
const DEPENDENCY_COLLECTOR_IMPL_BF= 'bf';

export function prepareExecutable(requirements: RequirementsData, workspacePath, javaConfig, context: ExtensionContext, isSyntaxServer: boolean): Executable {
export function prepareExecutable(requirements: RequirementsData, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): Executable {
const executable: Executable = Object.create(null);
const options: ExecutableOptions = Object.create(null);
options.env = Object.assign({ syntaxserver : isSyntaxServer }, process.env);
Expand All @@ -47,7 +47,7 @@ export function prepareExecutable(requirements: RequirementsData, workspacePath,
}
executable.options = options;
executable.command = path.resolve(`${requirements.tooling_jre}/bin/java`);
executable.args = prepareParams(requirements, javaConfig, workspacePath, context, isSyntaxServer);
executable.args = prepareParams(requirements, workspacePath, context, isSyntaxServer);
logger.info(`Starting Java server with: ${executable.command} ${executable.args.join(' ')}`);
return executable;
}
Expand All @@ -68,7 +68,7 @@ export function awaitServerConnection(port): Thenable<StreamInfo> {
});
}

function prepareParams(requirements: RequirementsData, javaConfiguration, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): string[] {
function prepareParams(requirements: RequirementsData, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): string[] {
const params: string[] = [];
if (DEBUG) {
const port = isSyntaxServer ? 1045 : 1044;
Expand Down Expand Up @@ -117,6 +117,9 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp
} else {
vmargs = '';
}
if (vmargs.indexOf('-DDetectVMInstallationsJob.disabled=') < 0) {
params.push('-DDetectVMInstallationsJob.disabled=true');
}
const encodingKey = '-Dfile.encoding=';
if (vmargs.indexOf(encodingKey) < 0) {
params.push(encodingKey + getJavaEncoding());
Expand Down
57 changes: 57 additions & 0 deletions src/jdkUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

import { IJavaRuntime, findRuntimes, getSources } from 'jdk-utils';

let cachedJdks: IJavaRuntime[];

export async function listJdks(force?: boolean): Promise<IJavaRuntime[]> {
if (force || !cachedJdks) {
cachedJdks = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
}

return [].concat(cachedJdks);
}

/**
* Sort by source where JDk is located.
* The order is:
* 1. JDK_HOME, JAVA_HOME, PATH
* 2. JDK manager such as SDKMAN, jEnv, jabba, asdf
* 3. Common places such as /usr/lib/jvm
* 4. Others
*/
export function sortJdksBySource(jdks: IJavaRuntime[]) {
const rankedJdks = jdks as Array<IJavaRuntime & { rank: number }>;
const env: string[] = ["JDK_HOME", "JAVA_HOME", "PATH"];
const jdkManagers: string[] = ["SDKMAN", "jEnv", "jabba", "asdf"];
for (const jdk of rankedJdks) {
const detectedSources: string[] = getSources(jdk);
for (const [index, source] of env.entries()) {
if (detectedSources.includes(source)) {
jdk.rank = index; // jdk from environment variables
break;
}
}

if (jdk.rank) {
continue;
}

const fromManager: boolean = detectedSources.some(source => jdkManagers.includes(source));
if (fromManager) {
jdk.rank = env.length + 1; // jdk from the jdk managers such as SDKMAN
} else if (!detectedSources.length){
jdk.rank = env.length + 2; // jdk from common places
} else {
jdk.rank = env.length + 3; // jdk from other source such as ~/.gradle/jdks
}
}
rankedJdks.sort((a, b) => a.rank - b.rank);
}

/**
* Sort by major version in descend order.
*/
export function sortJdksByVersion(jdks: IJavaRuntime[]) {
jdks.sort((a, b) => (b.version?.major ?? 0) - (a.version?.major ?? 0));
}
26 changes: 3 additions & 23 deletions src/requirements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import * as expandHomeDir from 'expand-home-dir';
import * as fse from 'fs-extra';
import { findRuntimes, getRuntime, getSources, IJavaRuntime, JAVAC_FILENAME, JAVA_FILENAME } from 'jdk-utils';
import { getRuntime, getSources, JAVAC_FILENAME, JAVA_FILENAME } from 'jdk-utils';
import * as path from 'path';
import { env, ExtensionContext, Uri, window, workspace } from 'vscode';
import { Commands } from './commands';
import { logger } from './log';
import { checkJavaPreferences } from './settings';
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';

const REQUIRED_JDK_VERSION = 17;
/* eslint-disable @typescript-eslint/naming-convention */
Expand Down Expand Up @@ -70,7 +71,7 @@ export async function resolveRequirements(context: ExtensionContext): Promise<Re
}

// search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
const javaRuntimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
const javaRuntimes = await listJdks();
if (!toolingJre) { // universal version
// as latest version as possible.
sortJdksByVersion(javaRuntimes);
Expand Down Expand Up @@ -159,27 +160,6 @@ async function findDefaultRuntimeFromSettings(): Promise<string | undefined> {
return undefined;
}

export function sortJdksBySource(jdks: IJavaRuntime[]) {
const rankedJdks = jdks as Array<IJavaRuntime & { rank: number }>;
const sources = ["JDK_HOME", "JAVA_HOME", "PATH"];
for (const [index, source] of sources.entries()) {
for (const jdk of rankedJdks) {
if (jdk.rank === undefined && getSources(jdk).includes(source)) {
jdk.rank = index;
}
}
}
rankedJdks.filter(jdk => jdk.rank === undefined).forEach(jdk => jdk.rank = sources.length);
rankedJdks.sort((a, b) => a.rank - b.rank);
}

/**
* Sort by major version in descend order.
*/
export function sortJdksByVersion(jdks: IJavaRuntime[]) {
jdks.sort((a, b) => (b.version?.major ?? 0) - (a.version?.major ?? 0));
}

export function parseMajorVersion(version: string): number {
if (!version) {
return 0;
Expand Down
9 changes: 4 additions & 5 deletions src/standardLanguageClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict';

import * as fse from 'fs-extra';
import { findRuntimes } from "jdk-utils";
import * as net from 'net';
import * as path from 'path';
import { CancellationToken, CodeActionKind, commands, ConfigurationTarget, DocumentSelector, EventEmitter, ExtensionContext, extensions, languages, Location, ProgressLocation, TextEditor, Uri, ViewColumn, window, workspace } from "vscode";
Expand All @@ -24,7 +22,7 @@ import { collectBuildFilePattern, onExtensionChange } from "./plugin";
import { pomCodeActionMetadata, PomCodeActionProvider } from "./pom/pomCodeActionProvider";
import { ActionableNotification, BuildProjectParams, BuildProjectRequest, CompileWorkspaceRequest, CompileWorkspaceStatus, EventNotification, EventType, ExecuteClientCommandRequest, FeatureStatus, FindLinks, GradleCompatibilityInfo, LinkLocation, ProgressKind, ProgressNotification, ServerNotification, SourceAttachmentAttribute, SourceAttachmentRequest, SourceAttachmentResult, SourceInvalidatedEvent, StatusNotification, UpgradeGradleWrapperInfo } from "./protocol";
import * as refactorAction from './refactorAction';
import { getJdkUrl, RequirementsData, sortJdksBySource, sortJdksByVersion } from "./requirements";
import { getJdkUrl, RequirementsData } from "./requirements";
import { serverStatus, ServerStatusKind } from "./serverStatus";
import { serverStatusBarProvider } from "./serverStatusBarProvider";
import { activationProgressNotification, serverTaskPresenter } from "./serverTaskPresenter";
Expand All @@ -41,6 +39,7 @@ import { Telemetry } from "./telemetry";
import { TelemetryEvent } from "@redhat-developer/vscode-redhat-telemetry/lib";
import { registerDocumentValidationListener } from './diagnostic';
import { registerSmartSemicolonDetection } from './smartSemicolonDetection';
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';

const extensionName = 'Language Support for Java';
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
Expand Down Expand Up @@ -91,7 +90,7 @@ export class StandardLanguageClient {
if (!port) {
const lsPort = process.env['JDTLS_CLIENT_PORT'];
if (!lsPort) {
serverOptions = prepareExecutable(requirements, workspacePath, getJavaConfig(requirements.java_home), context, false);
serverOptions = prepareExecutable(requirements, workspacePath, context, false);
} else {
serverOptions = () => {
const socket = net.connect(lsPort);
Expand Down Expand Up @@ -217,7 +216,7 @@ export class StandardLanguageClient {
const options: string[] = [];
const info = notification.data as GradleCompatibilityInfo;
const highestJavaVersion = Number(info.highestJavaVersion);
let runtimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
let runtimes = await listJdks(true);
runtimes = runtimes.filter(runtime => {
return runtime.version.major <= highestJavaVersion;
});
Expand Down
2 changes: 1 addition & 1 deletion src/syntaxLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class SyntaxLanguageClient {
didChangeConfiguration: async () => {
await this.languageClient.sendNotification(DidChangeConfigurationNotification.type, {
settings: {
java: getJavaConfig(requirements.java_home),
java: await getJavaConfig(requirements.java_home),
}
});
}
Expand Down
45 changes: 44 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as fs from 'fs';
import * as path from 'path';
import { workspace, WorkspaceConfiguration, commands, Uri, version } from 'vscode';
import { Commands } from './commands';
import { IJavaRuntime } from 'jdk-utils';
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';

export function getJavaConfiguration(): WorkspaceConfiguration {
return workspace.getConfiguration('java');
Expand Down Expand Up @@ -176,7 +178,7 @@ function getDirectoriesByBuildFile(inclusions: string[], exclusions: string[], f
}


export function getJavaConfig(javaHome: string) {
export async function getJavaConfig(javaHome: string) {
const origConfig = getJavaConfiguration();
const javaConfig = JSON.parse(JSON.stringify(origConfig));
javaConfig.home = javaHome;
Expand Down Expand Up @@ -215,5 +217,46 @@ export function getJavaConfig(javaHome: string) {
}

javaConfig.telemetry = { enabled: workspace.getConfiguration('redhat.telemetry').get('enabled', false) };
const userConfiguredJREs: any[] = javaConfig.configuration.runtimes;
javaConfig.configuration.runtimes = await addAutoDetectedJdks(userConfiguredJREs);
return javaConfig;
}

async function addAutoDetectedJdks(configuredJREs: any[]): Promise<any[]> {
// search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
const autoDetectedJREs: IJavaRuntime[] = await listJdks();
sortJdksByVersion(autoDetectedJREs);
sortJdksBySource(autoDetectedJREs);
const addedJreNames: Set<string> = new Set<string>();
for (const jre of configuredJREs) {
if (jre.name) {
addedJreNames.add(jre.name);
}
}
for (const jre of autoDetectedJREs) {
const majorVersion: number = jre.version?.major ?? 0;
if (!majorVersion) {
continue;
}

let jreName: string = `JavaSE-${majorVersion}`;
if (majorVersion <= 5) {
jreName = `J2SE-1.${majorVersion}`;
} else if (majorVersion <= 8) {
jreName = `JavaSE-1.${majorVersion}`;
}

if (addedJreNames.has(jreName)) {
continue;
}

configuredJREs.push({
name: jreName,
path: jre.homedir,
});

addedJreNames.add(jreName);
}

return configuredJREs;
}
Loading