From 0be2f1f4162e5c450419ac737af94146385b7926 Mon Sep 17 00:00:00 2001 From: Deepak Goyal Date: Wed, 14 May 2025 18:20:51 +0530 Subject: [PATCH 1/2] Java LSP Extension Bug Fix --- package.json | 7 +-- src/extension.ts | 5 ++ src/extensionDependencyValidator.ts | 87 +++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 src/extensionDependencyValidator.ts diff --git a/package.json b/package.json index cc7a3ac3..939f7db0 100644 --- a/package.json +++ b/package.json @@ -517,12 +517,9 @@ "test": "npm run compile && node ./out/test/index.js", "lint": "eslint -c .eslintrc.js --ext .ts ./src", "build-plugin": "node scripts/buildJdtlsExt.js", - "vscode:prepublish": "webpack --mode production" + "vscode:prepublish": "webpack --mode production", + "extension": "vsce package" }, - "extensionDependencies": [ - "redhat.java", - "vscjava.vscode-java-debug" - ], "devDependencies": { "@types/fs-extra": "^9.0.13", "@types/glob": "^7.2.0", diff --git a/src/extension.ts b/src/extension.ts index 24051eb2..82489cf5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -21,6 +21,7 @@ import { enableTests } from './commands/testDependenciesCommands'; import { testRunnerService } from './controller/testRunnerService'; import { TestRunner } from './java-test-runner.api'; import { parsePartsFromTestId, parseTestIdFromParts } from './utils/testItemUtils'; +import { waitForExtensionDependencies } from './extensionDependencyValidator'; export let extensionContext: ExtensionContext; let componentsRegistered: boolean = false; @@ -32,6 +33,10 @@ export async function activate(context: ExtensionContext): Promise { replacementString: 'Path must include project and resource name: /', }]}); await initExpService(context); + const extensionDependenciesResolved: boolean = await waitForExtensionDependencies(); + if (!extensionDependenciesResolved) { + return; + } await instrumentOperation('activation', doActivate)(context); return { registerTestProfile: (name: string, kind: TestRunProfileKind, runner: TestRunner) => { diff --git a/src/extensionDependencyValidator.ts b/src/extensionDependencyValidator.ts new file mode 100644 index 00000000..0c71f697 --- /dev/null +++ b/src/extensionDependencyValidator.ts @@ -0,0 +1,87 @@ +/** + * HackerRank-Specific Logic + * Dynamically waits for a list of extension dependencies to become available and active, + * replacing static extensionDependencies in package.json. + * - Waits up to 2 minutes total (not per extension), + * - Checks availability and attempts activation in parallel, + * - Fails only if any required extension fails to activate within the total timeout. + */ + +import { extensions, Extension, OutputChannel, window } from 'vscode'; + +// Create an OutputChannel for logging +const logger: OutputChannel = window.createOutputChannel('Java Test Runner'); + +const WAIT_TIME_MS: number = 3000; // 3 seconds +const MAX_ATTEMPTS: number = 40; // 40 attempts * 3 seconds = 120 seconds (2 minutes) + + +/** + * Waits for a single extension to activate within a timeout window. + */ +async function waitForExtension(depId: string): Promise { + for (let attempt: number = 0; attempt < MAX_ATTEMPTS; attempt++) { + const ext: Extension | undefined = extensions.getExtension(depId); + const timeElapsedSec: number = ((attempt + 1) * WAIT_TIME_MS) / 1000; + if (ext) { + try { + if (!ext.isActive) { + logger.appendLine( + `[waitDeps] [${depId}][${timeElapsedSec}s] Found but not active. Activating...` + ); + await ext.activate(); + } + + if (ext.isActive) { + logger.appendLine(`[waitDeps] [${depId}] Activated successfully.`); + return true; + } + } catch (e) { + logger.appendLine( + `[waitDeps] [${depId}][${timeElapsedSec}s] Activation failed: ${e}` + ); + } + } else { + logger.appendLine( + `[waitDeps] [${depId}][${timeElapsedSec}s] Not found. Retrying...` + ); + } + await new Promise((resolve: (value: void) => void) => + setTimeout(resolve, WAIT_TIME_MS) + ); + } + logger.appendLine(`[waitDeps] [${depId}] Failed to activate within 2 minutes.`); + return false; +} + +/** + * Waits for all required extensions in parallel. + * Returns true if all are activated, otherwise false. + */ +export async function waitForExtensionDependencies(): Promise { + logger.appendLine('[waitDeps] Checking for required extension dependencies...'); + const extensionDependencies: string[] = [ + 'redhat.java', + 'vscjava.vscode-java-debug' + ]; + const results: Record = {}; + await Promise.all( + extensionDependencies.map(async (depId: string) => { + logger.appendLine(`[waitDeps] Waiting for ${depId}...`); + results[depId] = await waitForExtension(depId); + }) + ); + const failed: string[] = Object.entries(results) + .filter(([, success]: [string, boolean]) => !success) + .map(([depId]: [string, boolean]) => depId); + const failedDepsString: string = `[${failed.join(', ')}]`; + if (failed.length > 0) { + logger.appendLine(`[waitDeps] Failed dependencies: ${failedDepsString}`); + window.showErrorMessage( + `Activation failed: Java Test Runner requires the ${failedDepsString} extension(s), but they did not activate in time.` + ); + return false; + } + logger.appendLine('[waitDeps] All dependencies activated successfully.'); + return true; +} \ No newline at end of file From 299025a28b4a1131af8c0cc6143e6789573747b5 Mon Sep 17 00:00:00 2001 From: Deepak Goyal Date: Wed, 14 May 2025 18:43:50 +0530 Subject: [PATCH 2/2] fix: increase wait time and max attempts in extensionDependencyValidator - Updated WAIT_TIME_MS from 3000 to 4000 milliseconds - Increased MAX_ATTEMPTS from 40 to 45 --- src/extensionDependencyValidator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extensionDependencyValidator.ts b/src/extensionDependencyValidator.ts index 0c71f697..e10f603d 100644 --- a/src/extensionDependencyValidator.ts +++ b/src/extensionDependencyValidator.ts @@ -12,8 +12,8 @@ import { extensions, Extension, OutputChannel, window } from 'vscode'; // Create an OutputChannel for logging const logger: OutputChannel = window.createOutputChannel('Java Test Runner'); -const WAIT_TIME_MS: number = 3000; // 3 seconds -const MAX_ATTEMPTS: number = 40; // 40 attempts * 3 seconds = 120 seconds (2 minutes) +const WAIT_TIME_MS: number = 4000; // 3 seconds +const MAX_ATTEMPTS: number = 45; // 40 attempts * 3 seconds = 120 seconds (2 minutes) /**