diff --git a/src/main/java/org/javacs/InferConfig.java b/src/main/java/org/javacs/InferConfig.java index 8cc004c5..046638a5 100644 --- a/src/main/java/org/javacs/InferConfig.java +++ b/src/main/java/org/javacs/InferConfig.java @@ -3,6 +3,7 @@ import com.google.devtools.build.lib.analysis.AnalysisProtos; import com.google.devtools.build.lib.analysis.AnalysisProtosV2; import com.google.devtools.build.lib.analysis.AnalysisProtosV2.PathFragment; + import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; @@ -11,6 +12,7 @@ import java.nio.file.Paths; import java.util.*; import java.util.logging.Logger; +import java.util.regex.*; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -19,14 +21,21 @@ 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 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, Collection externalDependencies, Path mavenHome, Path gradleHome) { + InferConfig( + Path workspaceRoot, + Collection externalDependencies, + Path mavenHome, + Path gradleHome) { this.workspaceRoot = workspaceRoot; this.externalDependencies = externalDependencies; this.mavenHome = mavenHome; @@ -49,36 +58,60 @@ private static Path defaultGradleHome() { return Paths.get(System.getProperty("user.home")).resolve(".gradle"); } - /** Find .jar files for external dependencies, for examples maven dependencies in ~/.m2 or jars in bazel-genfiles */ + /** + * Find .jar files for external dependencies, for examples maven dependencies in ~/.m2 or jars + * in bazel-genfiles + */ Set classPath() { + var result = new HashSet(); // externalDependencies if (!externalDependencies.isEmpty()) { - var result = new HashSet(); for (var id : externalDependencies) { var a = Artifact.parse(id); var found = findAnyJar(a, false); if (found == NOT_FOUND) { - LOG.warning(String.format("Couldn't find jar for %s in %s or %s", a, mavenHome, gradleHome)); + LOG.warning( + String.format( + "Couldn't find jar for %s in %s or %s", + a, mavenHome, gradleHome)); continue; } result.add(found); } - return result; + //return result; } // Maven var pomXml = workspaceRoot.resolve("pom.xml"); if (Files.exists(pomXml)) { - return mvnDependencies(pomXml, "dependency:list"); + var deps = mvnDependencies(pomXml, "dependency:list"); + result.addAll(deps); + LOG.warning("IIIIIIIIIIIIIIIIIIIIIIIIII pom deps size "+deps.size()); + } + + // Gradle + try { + createPomFromBuildGradle(); + var pom = workspaceRoot.resolve(".jls/pom.xml"); + LOG.warning("IIIIIIIIIIIIIIIIIIIIIIIIII pom ??? "+pom); + if (Files.exists(pom)) { + var deps = mvnDependencies(pom, "dependency:list"); + LOG.warning("IIIIIIIIIIIIIIIIIIIIIIIIII jls depssize "+deps.size()); + result.addAll(deps); + } + LOG.warning("IIIIIIIIIIIIIIIIIIIIIIIIII result "+result.size()); + } catch (IOException e) { + LOG.warning(e.getMessage()); } // Bazel var bazelWorkspaceRoot = bazelWorkspaceRoot(); if (Files.exists(bazelWorkspaceRoot.resolve("WORKSPACE"))) { - return bazelClasspath(bazelWorkspaceRoot); + result.addAll(bazelClasspath(bazelWorkspaceRoot)); } - return Collections.emptySet(); + LOG.warning("total dependencies size: " + result.size()); + return result; } private Path bazelWorkspaceRoot() { @@ -92,34 +125,49 @@ private Path bazelWorkspaceRoot() { /** Find source .jar files in local maven repository. */ Set buildDocPath() { + var result = new HashSet(); // externalDependencies if (!externalDependencies.isEmpty()) { - var result = new HashSet(); for (var id : externalDependencies) { var a = Artifact.parse(id); var found = findAnyJar(a, true); if (found == NOT_FOUND) { - LOG.warning(String.format("Couldn't find doc jar for %s in %s or %s", a, mavenHome, gradleHome)); + LOG.warning( + String.format( + "Couldn't find doc jar for %s in %s or %s", + a, mavenHome, gradleHome)); continue; } result.add(found); } - return result; + //return result; } // Maven var pomXml = workspaceRoot.resolve("pom.xml"); if (Files.exists(pomXml)) { - return mvnDependencies(pomXml, "dependency:sources"); + result.addAll(mvnDependencies(pomXml, "dependency:sources")); + } + + // Gradle + try { + createPomFromBuildGradle(); + var pom = workspaceRoot.resolve(".jls/pom.xml"); + if (Files.exists(pom)) { + result.addAll(mvnDependencies(pom, "dependency:sources")); + } + } catch (IOException e) { + LOG.warning(e.getMessage()); } // Bazel var bazelWorkspaceRoot = bazelWorkspaceRoot(); if (Files.exists(bazelWorkspaceRoot.resolve("WORKSPACE"))) { - return bazelSourcepath(bazelWorkspaceRoot); + result.addAll(bazelSourcepath(bazelWorkspaceRoot)); } - return Collections.emptySet(); + LOG.warning("total doc paths size: " + result.size()); + return result; } private Path findAnyJar(Artifact artifact, boolean source) { @@ -146,7 +194,8 @@ Path findMavenJar(Artifact artifact, boolean source) { } private Path findGradleJar(Artifact artifact, boolean source) { - // Search for caches/modules-*/files-*/groupId/artifactId/version/*/artifactId-version[-sources].jar + // Search for + // caches/modules-*/files-*/groupId/artifactId/version/*/artifactId-version[-sources].jar var base = gradleHome.resolve("caches"); var pattern = "glob:" @@ -176,7 +225,8 @@ private String fileName(Artifact artifact, boolean source) { static Set mvnDependencies(Path pomXml, String goal) { Objects.requireNonNull(pomXml, "pom.xml path is null"); try { - // TODO consider using mvn valide dependency:copy-dependencies -DoutputDirectory=??? instead + // TODO consider using mvn valide dependency:copy-dependencies -DoutputDirectory=??? + // instead // Run maven as a subprocess String[] command = { getMvnCommand(), @@ -265,14 +315,21 @@ private Set bazelClasspath(Path bazelWorkspaceRoot) { // Add protos if (buildProtos(bazelWorkspaceRoot)) { - for (var relative : bazelAQuery(bazelWorkspaceRoot, "Javac", "--output", "proto_library")) { + for (var relative : + bazelAQuery(bazelWorkspaceRoot, "Javac", "--output", "proto_library")) { absolute.add(bazelWorkspaceRoot.resolve(relative)); } } // Add rest of classpath for (var relative : - bazelAQuery(bazelWorkspaceRoot, "Javac", "--classpath", "java_library", "java_test", "java_binary")) { + bazelAQuery( + bazelWorkspaceRoot, + "Javac", + "--classpath", + "java_library", + "java_test", + "java_binary")) { absolute.add(bazelWorkspaceRoot.resolve(relative)); } return absolute; @@ -283,13 +340,19 @@ private Set bazelSourcepath(Path bazelWorkspaceRoot) { var outputBase = bazelOutputBase(bazelWorkspaceRoot); for (var relative : bazelAQuery( - bazelWorkspaceRoot, "JavaSourceJar", "--sources", "java_library", "java_test", "java_binary")) { + bazelWorkspaceRoot, + "JavaSourceJar", + "--sources", + "java_library", + "java_test", + "java_binary")) { absolute.add(outputBase.resolve(relative)); } // Add proto source files if (buildProtos(bazelWorkspaceRoot)) { - for (var relative : bazelAQuery(bazelWorkspaceRoot, "Javac", "--source_jars", "proto_library")) { + for (var relative : + bazelAQuery(bazelWorkspaceRoot, "Javac", "--source_jars", "proto_library")) { absolute.add(bazelWorkspaceRoot.resolve(relative)); } } @@ -355,7 +418,10 @@ private Set readQueryResult(Path output) { } private Set bazelAQuery( - Path bazelWorkspaceRoot, String filterMnemonic, String filterArgument, String... kinds) { + Path bazelWorkspaceRoot, + String filterMnemonic, + String filterArgument, + String... kinds) { String kindUnion = ""; for (var kind : kinds) { if (kindUnion.length() > 0) { @@ -381,18 +447,22 @@ private Set bazelAQuery( private Set readActionGraph(Path output, String filterArgument) { try { - var containerV2 = AnalysisProtosV2.ActionGraphContainer.parseFrom(Files.newInputStream(output)); - if (containerV2.getArtifactsCount() != 0 && containerV2.getArtifactsList().get(0).getId() != 0) { + var containerV2 = + AnalysisProtosV2.ActionGraphContainer.parseFrom(Files.newInputStream(output)); + if (containerV2.getArtifactsCount() != 0 + && containerV2.getArtifactsList().get(0).getId() != 0) { return readActionGraphFromV2(containerV2, filterArgument); } - var containerV1 = AnalysisProtos.ActionGraphContainer.parseFrom(Files.newInputStream(output)); + var containerV1 = + AnalysisProtos.ActionGraphContainer.parseFrom(Files.newInputStream(output)); return readActionGraphFromV1(containerV1, filterArgument); } catch (IOException e) { throw new RuntimeException(e); } } - private Set readActionGraphFromV1(AnalysisProtos.ActionGraphContainer container, String filterArgument) { + private Set readActionGraphFromV1( + AnalysisProtos.ActionGraphContainer container, String filterArgument) { var argumentPaths = new HashSet(); var outputIds = new HashSet(); for (var action : container.getActionsList()) { @@ -427,7 +497,8 @@ private Set readActionGraphFromV1(AnalysisProtos.ActionGraphContainer co return artifactPaths; } - private Set readActionGraphFromV2(AnalysisProtosV2.ActionGraphContainer container, String filterArgument) { + private Set readActionGraphFromV2( + AnalysisProtosV2.ActionGraphContainer container, String filterArgument) { var argumentPaths = new HashSet(); var outputIds = new HashSet(); for (var action : container.getActionsList()) { @@ -451,7 +522,8 @@ private Set readActionGraphFromV2(AnalysisProtosV2.ActionGraphContainer // artifact is the output of another java action continue; } - var relative = buildPath(container.getPathFragmentsList(), artifact.getPathFragmentId()); + var relative = + buildPath(container.getPathFragmentsList(), artifact.getPathFragmentId()); if (!argumentPaths.contains(relative)) { // artifact was not specified by --filterArgument continue; @@ -497,5 +569,112 @@ private static Path fork(Path workspaceRoot, String[] command) { } } + private void createPomFromBuildGradle() throws IOException { + Path gradleFilePath = Paths.get("build.gradle"); + Path pomFileName = Paths.get("pom.xml"); + Path pomDirectory = Paths.get(".jls"); + + List dependencies = new ArrayList<>(); + List platformDependencies = new ArrayList<>(); + + List lines = Files.readAllLines(gradleFilePath); + + // Pattern for implementation dependencies + Pattern implPattern = + Pattern.compile( + "implementation[\\s*\\(,\\(platform\\(]*['\"](.*?:)(.*?)(:.*?)['\"]"); + // Pattern for testImplementation dependencies + Pattern testImplPattern = + Pattern.compile( + "testImplementation[\\s*,\\(,\\(platform\\(]*['\"](.*?:)(.*?)(:.*?)?['\"]"); + + for (String line : lines) { + Matcher m = implPattern.matcher(line); + if (line.contains("platform")) { + if (m.find()) { + platformDependencies.add(new Dependency(m.group(1), m.group(2), m.group(3), false)); + } + m = testImplPattern.matcher(line); + if (m.find()) { + platformDependencies.add(new Dependency(m.group(1), m.group(2), m.group(3), true)); + } + } else { + if (m.find()) { + dependencies.add(new Dependency(m.group(1), m.group(2), m.group(3), false)); + } + m = testImplPattern.matcher(line); + if (m.find()) { + dependencies.add(new Dependency(m.group(1), m.group(2), m.group(3), true)); + } + } + } + + // Generate basic pom.xml + StringBuilder pom = new StringBuilder(); + pom.append("\n"); + pom.append("\n"); + pom.append(" 4.0.0\n"); + + // Placeholder project info + pom.append(" com.example\n"); + pom.append(" my-app\n"); + pom.append(" 1.0-SNAPSHOT\n"); + + pom.append(" \n"); + pom.append(" \n"); + for (Dependency dep : platformDependencies) { + pom.append(" \n"); + pom.append(" ") + .append(dep.groupId.replace(":", "")) + .append("\n"); + pom.append(" ").append(dep.artifactId).append("\n"); + if (dep.version != null) { + pom.append(" ") + .append(dep.version.replace(":", "")) + .append("\n"); + } + pom.append(" pom\n"); + if (dep.isTest) { + pom.append(" test\n"); + } + pom.append(" \n"); + } + pom.append(" \n"); + pom.append(" \n"); + pom.append(" \n"); + + for (Dependency dep : dependencies) { + pom.append(" \n"); + pom.append(" ") + .append(dep.groupId.replace(":", "")) + .append("\n"); + pom.append(" ").append(dep.artifactId).append("\n"); + if (dep.version != null) { + pom.append(" ") + .append(dep.version.replace(":", "")) + .append("\n"); + } + if (dep.isTest) { + pom.append(" test\n"); + } + pom.append(" \n"); + } + + pom.append(" \n"); + + pom.append("\n"); + + // Write to pom.xml + if (!Files.exists(pomDirectory)) { + Files.createDirectory(pomDirectory); + } + Files.write(pomDirectory.resolve(pomFileName), pom.toString().getBytes()); + } + + record Dependency(String groupId, String artifactId, String version, boolean isTest) {} + private static final Path NOT_FOUND = Paths.get(""); }