diff options
author | George Fraser <george@fivetran.com> | 2018-09-16 10:30:38 -0700 |
---|---|---|
committer | George Fraser <george@fivetran.com> | 2018-09-16 10:30:38 -0700 |
commit | e60ee6dc55943e0252cc3dbb66a5ffcc453d4b78 (patch) | |
tree | 04bee4226dcb4e356ece4569899563e9e37514b0 | |
parent | 2f20929eaa41bb0af83340b935e9ccd0361e51a3 (diff) | |
download | java-language-server-e60ee6dc55943e0252cc3dbb66a5ffcc453d4b78.zip |
Revive externalDependencies and classPath
-rwxr-xr-x | scripts/build.sh | 2 | ||||
-rw-r--r-- | scripts/build.sh~HEAD | 3 | ||||
-rw-r--r-- | scripts/test.sh | 3 | ||||
-rw-r--r-- | src/main/java/org/javacs/InferConfig.java | 131 | ||||
-rw-r--r-- | src/main/java/org/javacs/JavaLanguageServer.java | 36 | ||||
-rw-r--r-- | src/main/java/org/javacs/JavaWorkspaceService.java | 19 | ||||
-rw-r--r-- | src/test/java/org/javacs/InferBazelConfigTest.java | 4 | ||||
-rw-r--r-- | src/test/java/org/javacs/InferConfigTest.java | 62 |
8 files changed, 209 insertions, 51 deletions
diff --git a/scripts/build.sh b/scripts/build.sh index 2e6adf4..bb64d2d 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -4,8 +4,6 @@ # You will need java, maven, vsce, and visual studio code to run this script set -e -export JAVA_HOME=`/usr/libexec/java_home -v 1.8` - # Needed once npm install diff --git a/scripts/build.sh~HEAD b/scripts/build.sh~HEAD deleted file mode 100644 index 559c330..0000000 --- a/scripts/build.sh~HEAD +++ /dev/null @@ -1,3 +0,0 @@ -export JAVA_HOME=`/usr/libexec/java_home -v 1.8` - -mvn compile
\ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh deleted file mode 100644 index 15facd5..0000000 --- a/scripts/test.sh +++ /dev/null @@ -1,3 +0,0 @@ -export JAVA_HOME=`/usr/libexec/java_home -v 1.8` - -mvn test
\ No newline at end of file diff --git a/src/main/java/org/javacs/InferConfig.java b/src/main/java/org/javacs/InferConfig.java index 341eb0f..5803260 100644 --- a/src/main/java/org/javacs/InferConfig.java +++ b/src/main/java/org/javacs/InferConfig.java @@ -25,22 +25,36 @@ class InferConfig { /** Root of the workspace that is currently open in VSCode */ private final Path workspaceRoot; + /** External dependencies specified manually by the user */ + private final Collection<String> externalDependencies; /** Location of the maven repository, usually ~/.m2 */ private final Path mavenHome; + /** Location of the gradle cache, usually ~/.gradle */ + private final Path gradleHome; - InferConfig(Path workspaceRoot, Path mavenHome) { + InferConfig(Path workspaceRoot, Collection<String> externalDependencies, Path mavenHome, Path gradleHome) { this.workspaceRoot = workspaceRoot; + this.externalDependencies = externalDependencies; this.mavenHome = mavenHome; + this.gradleHome = gradleHome; + } + + InferConfig(Path workspaceRoot, Collection<String> externalDependencies) { + this(workspaceRoot, externalDependencies, defaultMavenHome(), defaultGradleHome()); } InferConfig(Path workspaceRoot) { - this(workspaceRoot, defaultMavenHome()); + this(workspaceRoot, Collections.emptySet(), defaultMavenHome(), defaultGradleHome()); } private static Path defaultMavenHome() { return Paths.get(System.getProperty("user.home")).resolve(".m2"); } + private static Path defaultGradleHome() { + return Paths.get(System.getProperty("user.home")).resolve(".gradle"); + } + Set<Path> classPath() { var result = new HashSet<Path>(); result.addAll(buildClassPath()); @@ -50,24 +64,32 @@ class InferConfig { /** Find .jar files for external dependencies, for examples maven dependencies in ~/.m2 or jars in bazel-genfiles */ Set<Path> buildClassPath() { - var result = new HashSet<Path>(); + // externalDependencies + if (!externalDependencies.isEmpty()) { + var result = new HashSet<Path>(); + for (var id : externalDependencies) { + var a = Artifact.parse(id); + var found = findAnyJar(a, false); + if (found.isPresent()) result.add(found.get()); + else LOG.warning(String.format("Couldn't find jar for %s in %s or %s", a, mavenHome, gradleHome)); + } + return result; + } // Maven - var as = mvnDependencies(); - if (!as.isEmpty()) { - LOG.info("Looking for artifacts:"); - for (var a : as) { - System.err.println(" " + a); + if (Files.exists(workspaceRoot.resolve("pom.xml"))) { + var result = new HashSet<Path>(); + for (var a : mvnDependencies()) { + var found = findMavenJar(a, false); + if (found.isPresent()) result.add(found.get()); + else LOG.warning(String.format("Couldn't find jar for %s in %s", a, mavenHome)); } - } - for (var a : as) { - var found = findMavenJar(a, false); - if (found.isPresent()) result.add(found.get()); - else LOG.warning(String.format("Couldn't find jar for %s in %s", a, mavenHome)); + return result; } // Bazel if (Files.exists(workspaceRoot.resolve("WORKSPACE"))) { + var result = new HashSet<Path>(); var bazelGenFiles = workspaceRoot.resolve("bazel-genfiles"); if (Files.exists(bazelGenFiles) && Files.isSymbolicLink(bazelGenFiles)) { @@ -76,9 +98,10 @@ class InferConfig { LOG.info(String.format("Found %d generated-files directories", jars.size())); result.addAll(jars); } + return result; } - return result; + return Collections.emptySet(); } /** @@ -86,6 +109,20 @@ class InferConfig { * target/classes */ Set<Path> workspaceClassPath() { + // externalDependencies + if (!externalDependencies.isEmpty()) { + return Collections.emptySet(); + } + + // Maven + if (Files.exists(workspaceRoot.resolve("pom.xml"))) { + try { + return Files.walk(workspaceRoot).flatMap(this::outputDirectory).collect(Collectors.toSet()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + // Bazel if (Files.exists(workspaceRoot.resolve("WORKSPACE"))) { var bazelBin = workspaceRoot.resolve("bazel-bin"); @@ -95,12 +132,7 @@ class InferConfig { } } - // Maven - try { - return Files.walk(workspaceRoot).flatMap(this::outputDirectory).collect(Collectors.toSet()); - } catch (IOException e) { - throw new RuntimeException(e); - } + return Collections.emptySet(); } /** Recognize build root files like pom.xml and return compiler output directories */ @@ -173,15 +205,39 @@ class InferConfig { } } - /** Find source .jar files for `externalDependencies` in local maven / gradle repository. */ + /** Find source .jar files in local maven repository. */ Set<Path> buildDocPath() { - var result = new HashSet<Path>(); + // externalDependencies + if (!externalDependencies.isEmpty()) { + var result = new HashSet<Path>(); + for (var id : externalDependencies) { + var a = Artifact.parse(id); + var found = findAnyJar(a, true); + if (found.isPresent()) result.add(found.get()); + else LOG.warning(String.format("Couldn't find doc jar for %s in %s or %s", a, mavenHome, gradleHome)); + } + return result; + } + // Maven - for (var a : mvnDependencies()) { - findMavenJar(a, true).ifPresent(result::add); + if (Files.exists(workspaceRoot.resolve("pom.xml"))) { + var result = new HashSet<Path>(); + for (var a : mvnDependencies()) { + findMavenJar(a, true).ifPresent(result::add); + } + return result; } + // TODO Bazel - return result; + + return Collections.emptySet(); + } + + private Optional<Path> findAnyJar(Artifact artifact, boolean source) { + Optional<Path> maven = findMavenJar(artifact, source); + + if (maven.isPresent()) return maven; + else return findGradleJar(artifact, source); } Optional<Path> findMavenJar(Artifact artifact, boolean source) { @@ -197,6 +253,30 @@ class InferConfig { else return Optional.empty(); } + private Optional<Path> findGradleJar(Artifact artifact, boolean source) { + // Search for caches/modules-*/files-*/groupId/artifactId/version/*/artifactId-version[-sources].jar + var base = gradleHome.resolve("caches"); + var pattern = + "glob:" + + String.join( + File.separator, + base.toString(), + "modules-*", + "files-*", + artifact.groupId, + artifact.artifactId, + artifact.version, + "*", + fileName(artifact, source)); + var match = FileSystems.getDefault().getPathMatcher(pattern); + + try { + return Files.walk(base, 7).filter(match::matches).findFirst(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + private String fileName(Artifact artifact, boolean source) { return artifact.artifactId + '-' + artifact.version + (source ? "-sources" : "") + ".jar"; } @@ -237,7 +317,6 @@ class InferConfig { } } - /** Get external dependencies from this.externalDependencies if available, or try to infer them. */ private Collection<Artifact> mvnDependencies() { var pomXml = workspaceRoot.resolve("pom.xml"); diff --git a/src/main/java/org/javacs/JavaLanguageServer.java b/src/main/java/org/javacs/JavaLanguageServer.java index 01e301d..eb2d68f 100644 --- a/src/main/java/org/javacs/JavaLanguageServer.java +++ b/src/main/java/org/javacs/JavaLanguageServer.java @@ -6,8 +6,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -19,8 +21,11 @@ import org.eclipse.lsp4j.services.*; class JavaLanguageServer implements LanguageServer { private static final Logger LOG = Logger.getLogger("main"); - Path workspaceRoot; - LanguageClient client; + private Path workspaceRoot; + private LanguageClient client; + private Set<String> externalDependencies = Set.of(); + private Set<Path> classPath = Set.of(); + JavaCompilerService compiler; final JavaTextDocumentService textDocuments = new JavaTextDocumentService(this); final JavaWorkspaceService workspace = new JavaWorkspaceService(this); @@ -84,9 +89,30 @@ class JavaLanguageServer implements LanguageServer { private JavaCompilerService createCompiler() { Objects.requireNonNull(workspaceRoot, "Can't create compiler because workspaceRoot has not been initialized"); - var infer = new InferConfig(workspaceRoot); - return new JavaCompilerService( - InferSourcePath.sourcePath(workspaceRoot), infer.classPath(), infer.buildDocPath()); + + // If classpath is specified by the user, don't infer anything + if (!classPath.isEmpty()) { + return new JavaCompilerService( + InferSourcePath.sourcePath(workspaceRoot), classPath, Collections.emptySet()); + } + // Otherwise, combine inference with user-specified external dependencies + else { + var infer = new InferConfig(workspaceRoot, externalDependencies); + return new JavaCompilerService( + InferSourcePath.sourcePath(workspaceRoot), infer.classPath(), infer.buildDocPath()); + } + } + + void setExternalDependencies(Set<String> externalDependencies) { + var changed = this.externalDependencies.isEmpty() != externalDependencies.isEmpty(); + this.externalDependencies = externalDependencies; + if (changed) this.compiler = createCompiler(); + } + + void setClassPath(Set<Path> classPath) { + var changed = this.classPath.isEmpty() != classPath.isEmpty(); + this.classPath = classPath; + if (changed) this.compiler = createCompiler(); } @Override diff --git a/src/main/java/org/javacs/JavaWorkspaceService.java b/src/main/java/org/javacs/JavaWorkspaceService.java index 13c5e70..998fb5c 100644 --- a/src/main/java/org/javacs/JavaWorkspaceService.java +++ b/src/main/java/org/javacs/JavaWorkspaceService.java @@ -1,5 +1,9 @@ package org.javacs; +import com.google.gson.JsonObject; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashSet; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.logging.Logger; @@ -37,7 +41,20 @@ class JavaWorkspaceService implements WorkspaceService { } @Override - public void didChangeConfiguration(DidChangeConfigurationParams change) {} + public void didChangeConfiguration(DidChangeConfigurationParams change) { + var settings = (JsonObject) change.getSettings(); + var java = settings.getAsJsonObject("java"); + + var externalDependencies = java.getAsJsonArray("externalDependencies"); + var strings = new HashSet<String>(); + for (var each : externalDependencies) strings.add(each.getAsString()); + server.setExternalDependencies(strings); + + var classPath = java.getAsJsonArray("classPath"); + var paths = new HashSet<Path>(); + for (var each : classPath) paths.add(Paths.get(each.getAsString()).toAbsolutePath()); + server.setClassPath(paths); + } @Override public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {} diff --git a/src/test/java/org/javacs/InferBazelConfigTest.java b/src/test/java/org/javacs/InferBazelConfigTest.java index d3e04fc..f5dcd80 100644 --- a/src/test/java/org/javacs/InferBazelConfigTest.java +++ b/src/test/java/org/javacs/InferBazelConfigTest.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -15,7 +16,8 @@ public class InferBazelConfigTest { private Path bazelWorkspace = Paths.get("src/test/test-project/bazel-workspace"), bazelTemp = Paths.get("src/test/test-project/bazel-temp"); - private InferConfig bazel = new InferConfig(bazelWorkspace, Paths.get("nowhere")); + private InferConfig bazel = + new InferConfig(bazelWorkspace, Collections.emptySet(), Paths.get("nowhere"), Paths.get("nowhere")); private Path bazelBin = bazelWorkspace.resolve("bazel-bin"), bazelBinTarget = bazelTemp.resolve("xyz/execroot/test/bazel-out/local-fastbuild/bin").toAbsolutePath(), bazelGenfiles = bazelWorkspace.resolve("bazel-genfiles"), diff --git a/src/test/java/org/javacs/InferConfigTest.java b/src/test/java/org/javacs/InferConfigTest.java index 2a951cc..debd6db 100644 --- a/src/test/java/org/javacs/InferConfigTest.java +++ b/src/test/java/org/javacs/InferConfigTest.java @@ -5,40 +5,82 @@ import static org.junit.Assert.*; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; +import java.util.Set; import org.junit.Test; public class InferConfigTest { private Path workspaceRoot = Paths.get("src/test/test-project/workspace"); private Path mavenHome = Paths.get("src/test/test-project/home/.m2"); - private Artifact externalArtifact = new Artifact("com.external", "external-library", "1.2"); - private InferConfig infer = new InferConfig(workspaceRoot, mavenHome); + private Path gradleHome = Paths.get("src/test/test-project/home/.gradle"); + private Set<String> externalDependencies = Set.of("com.external:external-library:1.2"); + private InferConfig both = new InferConfig(workspaceRoot, externalDependencies, mavenHome, gradleHome); + private InferConfig gradle = new InferConfig(workspaceRoot, externalDependencies, Paths.get("nowhere"), gradleHome); + private InferConfig onlyPomXml = + new InferConfig( + Paths.get("src/test/test-project/only-pom-xml"), + Collections.emptySet(), + mavenHome, + Paths.get("nowhere")); @Test public void mavenClassPath() { - var found = infer.findMavenJar(externalArtifact, false); - assertTrue(found.isPresent()); assertThat( - found.get(), - equalTo(mavenHome.resolve("repository/com/external/external-library/1.2/external-library-1.2.jar"))); + both.buildClassPath(), + contains(mavenHome.resolve("repository/com/external/external-library/1.2/external-library-1.2.jar"))); + // v1.1 should be ignored + } + + @Test + public void gradleClasspath() { + assertThat( + gradle.buildClassPath(), + contains( + gradleHome.resolve( + "caches/modules-2/files-2.1/com.external/external-library/1.2/xxx/external-library-1.2.jar"))); // v1.1 should be ignored } @Test public void mavenDocPath() { - var found = infer.findMavenJar(externalArtifact, true); - assertTrue(found.isPresent()); assertThat( - found.get(), - equalTo( + both.buildDocPath(), + contains( mavenHome.resolve( "repository/com/external/external-library/1.2/external-library-1.2-sources.jar"))); // v1.1 should be ignored } @Test + public void gradleDocPath() { + assertThat( + gradle.buildDocPath(), + contains( + gradleHome.resolve( + "caches/modules-2/files-2.1/com.external/external-library/1.2/yyy/external-library-1.2-sources.jar"))); + // v1.1 should be ignored + } + + @Test public void dependencyList() { assertThat( InferConfig.dependencyList(Paths.get("pom.xml")), hasItem(new Artifact("org.hamcrest", "hamcrest-all", "1.3"))); } + + @Test + public void onlyPomXmlClassPath() { + assertThat( + onlyPomXml.buildClassPath(), + contains(mavenHome.resolve("repository/com/external/external-library/1.2/external-library-1.2.jar"))); + } + + @Test + public void onlyPomXmlDocPath() { + assertThat( + onlyPomXml.buildDocPath(), + contains( + mavenHome.resolve( + "repository/com/external/external-library/1.2/external-library-1.2-sources.jar"))); + } } |