Skip to content

Commit

Permalink
http-client-java, fix eclipse languageserver when tmp folder is corru…
Browse files Browse the repository at this point in the history
…pted (#5307)

### Situation
I somehow encountered a folder corruption situation that the tmp folder
for language server is there, but with no Jar file. Language server
didn't start correctly, but the exception is thrown only when JSON RPC
to the server is performed.
<img width="1406" alt="Screenshot 2024-12-11 at 14 23 52"
src="https://github.com/user-attachments/assets/1654fabc-bb71-4b81-aab7-b4c24b8afae3">


### This PR
- In case the language server did not start correctly, and user did not
explicitly provide a language server path, force a re-download.
- If the server failed to start anyway, throw with the process output.

### Test
#### Normal first download
<img width="1372" alt="Screenshot 2024-12-09 at 20 12 06"
src="https://github.com/user-attachments/assets/9126e436-cad2-4a03-9d7c-cb31d5bc4a95">


#### Normal downloaded
<img width="1251" alt="Screenshot 2024-12-09 at 20 09 22"
src="https://github.com/user-attachments/assets/2deb6fb3-acef-4d4b-8365-8a6ebf3ab3f8">


#### Corrupted folder, we do a re-download
<img width="1306" alt="Screenshot 2024-12-09 at 20 08 35"
src="https://github.com/user-attachments/assets/d8d56d6f-fd97-4b06-8327-08045cbadbff">

#### Server failed to start anyway, we throw with server output
<img width="1383" alt="Screenshot 2024-12-10 at 16 48 25"
src="https://github.com/user-attachments/assets/36f56e7d-0b58-4820-8c6f-a33dc559c902">
  • Loading branch information
XiaofeiCao authored Dec 11, 2024
1 parent f21484e commit a862ac7
Showing 1 changed file with 57 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
package com.microsoft.typespec.http.client.generator.core.customization.implementation.ls;

import com.microsoft.typespec.http.client.generator.core.customization.implementation.Utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.URI;
Expand All @@ -16,6 +18,7 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
Expand All @@ -33,7 +36,7 @@ public EclipseLanguageServerFacade(String pathToLanguageServerPlugin, Logger log
int javaVersion = Runtime.version().feature();

Path languageServerPath = (pathToLanguageServerPlugin == null)
? getLanguageServerDirectory(javaVersion, logger)
? getLanguageServerDirectory(javaVersion, logger, false)
: Paths.get(pathToLanguageServerPlugin).resolve("jdt-language-server");

List<String> command = new ArrayList<>();
Expand Down Expand Up @@ -71,18 +74,55 @@ public EclipseLanguageServerFacade(String pathToLanguageServerPlugin, Logger log
command.add("./config_linux");
}

logger.info("Starting Eclipse JDT language server at {}", languageServerPath);
server = new ProcessBuilder(command).redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectInput(ProcessBuilder.Redirect.PIPE)
.redirectErrorStream(true)
.directory(languageServerPath.toFile())
.start();
Process server = startServer(command, languageServerPath, logger);
if (!server.isAlive()) {
if (pathToLanguageServerPlugin == null) {
// If user didn't specify language server path, we do a clean re-download.
logger
.warn("Eclipse language server failed to start. The folder may be corrupted. Try re-download.");
server = startServer(command, getLanguageServerDirectory(javaVersion, logger, true), logger);
if (!server.isAlive()) {
// if server failed to start anyway, throw with server output.
throw new RuntimeException(String.format(
"Eclipse language server failed to start, error output:\n %s", readServerOutput(server)));
}
} else {
// if user specify the language server path, we just throw with server output.
throw new RuntimeException(String.format(
"Eclipse language server failed to start, error output:\n %s", readServerOutput(server)));
}
}
this.server = server;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static Path getLanguageServerDirectory(int javaVersion, Logger logger) throws IOException {
private String readServerOutput(Process server) throws IOException {
if (server.getInputStream() == null) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream()))) {
reader.lines().forEachOrdered(line -> stringBuilder.append(line).append("\n"));
}
return stringBuilder.toString();
}

private Process startServer(List<String> command, Path languageServerPath, Logger logger) throws Exception {
logger.info("Starting Eclipse JDT language server at {}", languageServerPath);
final Process server;
server = new ProcessBuilder(command).redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectInput(ProcessBuilder.Redirect.PIPE)
.redirectErrorStream(true)
.directory(languageServerPath.toFile())
.start();
server.waitFor(1, TimeUnit.SECONDS);
return server;
}

private static Path getLanguageServerDirectory(int javaVersion, Logger logger, boolean forceReDownload)
throws IOException {
Path tmp = Paths.get(System.getProperty("java.io.tmpdir"));
Path autorestLanguageServer = tmp.resolve("autorest-java-language-server");

Expand All @@ -104,9 +144,12 @@ private static Path getLanguageServerDirectory(int javaVersion, Logger logger) t
}

Path languageServer = languageServerPath.resolve("jdt-language-server");
if (!Files.exists(languageServerPath) || !Files.exists(languageServer)) {
Files.createDirectories(languageServerPath);

if (!Files.exists(languageServer) || forceReDownload) {
Files.createDirectories(languageServer);
Path zipPath = languageServerPath.resolve("jdt-language-server.tar.gz");
Files.deleteIfExists(zipPath);

logger.info("Downloading Eclipse JDT language server from {} to {}", downloadUrl, zipPath);
try (InputStream in = downloadUrl.openStream()) {
Files.copy(in, zipPath);
Expand All @@ -122,13 +165,15 @@ private static Path getLanguageServerDirectory(int javaVersion, Logger logger) t
private static Path unzipLanguageServer(Path zipPath) throws IOException {
try (TarInputStream tar = new TarInputStream(new GZIPInputStream(Files.newInputStream(zipPath)))) {
Path languageServerDirectory = zipPath.getParent().resolve("jdt-language-server");
Files.createDirectory(languageServerDirectory);
TarEntry entry;
while ((entry = tar.getNextEntry()) != null) {
if (entry.isDirectory()) {
Files.createDirectories(languageServerDirectory.resolve(entry.getName()));
} else {
Files.copy(tar, languageServerDirectory.resolve(entry.getName()));
Path entryPath = languageServerDirectory.resolve(entry.getName());
// In case of corrupted folder, delete before create.
Files.deleteIfExists(entryPath);
Files.copy(tar, entryPath);
}
}

Expand Down

0 comments on commit a862ac7

Please sign in to comment.