diff --git a/packages/metals-languageclient/src/__tests__/setupCoursier.test.ts b/packages/metals-languageclient/src/__tests__/setupCoursier.test.ts index 36879640..09c49ba2 100644 --- a/packages/metals-languageclient/src/__tests__/setupCoursier.test.ts +++ b/packages/metals-languageclient/src/__tests__/setupCoursier.test.ts @@ -49,6 +49,7 @@ describe("setupCoursier", () => { const { coursier, javaHome } = await setupCoursier( "17", tmpDir, + process.cwd(), new LogOutputChannel() ); expect(fs.existsSync(coursier)).toBeTruthy; diff --git a/packages/metals-languageclient/src/fetchMetals.ts b/packages/metals-languageclient/src/fetchMetals.ts index 30423f73..092553eb 100644 --- a/packages/metals-languageclient/src/fetchMetals.ts +++ b/packages/metals-languageclient/src/fetchMetals.ts @@ -21,7 +21,7 @@ interface PackedChildPromise { export async function fetchMetals({ serverVersion, serverProperties, - javaConfig: { javaOptions, coursier, extraEnv }, + javaConfig: { javaOptions, coursier, extraEnv, javaPath }, outputChannel, }: FetchMetalsOptions): Promise { const serverDependency = calcServerDependency(serverVersion); @@ -35,11 +35,7 @@ export async function fetchMetals({ ); } - // Convert Java properties to the "-J" argument form used by Coursier - const javaArgs = javaOptions.concat(fetchProperties).map((p) => `-J${p}`); - const coursierArgs = [ - ...javaArgs, "fetch", "-p", "--ttl", @@ -64,9 +60,22 @@ export async function fetchMetals({ }, }; - return { - promise: spawn(coursier, coursierArgs, environment), - }; + if (coursier.endsWith(".jar")) { + const jarArgs = [ + ...javaOptions, + ...fetchProperties, + "-Dfile.encoding=UTF-8", + "-jar", + coursier, + ].concat(coursierArgs); + return { promise: spawn(javaPath, jarArgs, environment) }; + } else { + // Convert Java properties to the "-J" argument form used by Coursier + const javaArgs = javaOptions.concat(fetchProperties).map((p) => `-J${p}`); + return { + promise: spawn(coursier, javaArgs.concat(coursierArgs), environment), + }; + } } export function calcServerDependency(serverVersion: string): string { diff --git a/packages/metals-languageclient/src/setupCoursier.ts b/packages/metals-languageclient/src/setupCoursier.ts index 8fa054d9..767394df 100644 --- a/packages/metals-languageclient/src/setupCoursier.ts +++ b/packages/metals-languageclient/src/setupCoursier.ts @@ -18,6 +18,7 @@ const coursierCommit = "11b428f35ca84a598ca30cce1c35ae4f375e5ee3"; export async function setupCoursier( javaVersion: JavaVersion, coursierFetchPath: string, + extensionPath: string, output: OutputChannel ): Promise<{ coursier: string; javaHome: string }> { const handleOutput = (out: Buffer) => { @@ -40,11 +41,14 @@ export async function setupCoursier( return fetchCoursier(coursierFetchPath, handleOutput) .then(() => defaultCoursier) - .catch((err) => { + .catch((_) => { output.appendLine( "Failed to fetch coursier. You may want to try installing coursier manually and adding it to PATH." ); - throw err; + output.appendLine( + "Will try to use jar based coursier if Java is available on the machine." + ); + return undefined; }); }; @@ -67,12 +71,12 @@ export async function setupCoursier( return ((await getJavaPath).stdout as string).trim(); }; - const coursier = await resolveCoursier(); + var coursier = await resolveCoursier(); output.appendLine(`Using coursier located at ${coursier}`); var javaHome = await getJavaHome(javaVersion, output); - if (!javaHome) { + if (!javaHome && coursier) { output.appendLine( `No installed java with version ${javaVersion} found. Will fetch one using coursier.` ); @@ -81,7 +85,18 @@ export async function setupCoursier( output.appendLine(`Using Java Home: ${javaHome}`); - return { coursier, javaHome }; + /* If we couldn't download coursier, but we have Java + * we can still fall back to jar based launcher. + */ + if (!coursier && javaHome) { + coursier = path.join(extensionPath, "./coursier-fallback.jar"); + } + + if (javaHome && coursier) return { coursier, javaHome }; + else + throw Error( + "Cannot resolve Java home or coursier, please provide at least JAVA_HOME." + ); } export async function validateCoursier( diff --git a/packages/metals-vscode/coursier-fallback.jar b/packages/metals-vscode/coursier-fallback.jar new file mode 100755 index 00000000..a664bdf8 Binary files /dev/null and b/packages/metals-vscode/coursier-fallback.jar differ diff --git a/packages/metals-vscode/src/extension.ts b/packages/metals-vscode/src/extension.ts index 032b570a..1b7a8292 100644 --- a/packages/metals-vscode/src/extension.ts +++ b/packages/metals-vscode/src/extension.ts @@ -142,6 +142,7 @@ export async function activate(context: ExtensionContext): Promise { await fetchAndLaunchMetals(context, serverVersion, javaVersion); } catch (err) { outputChannel.appendLine(`${err}`); + window.showErrorMessage(`${err}`); } } ); @@ -217,6 +218,7 @@ async function fetchAndLaunchMetals( const { coursier, javaHome } = await metalsLanguageClient.setupCoursier( javaVersion, metalsDirPath, + context.extensionPath, outputChannel );