diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml b/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml index 0759c2127..c9453ba38 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml @@ -504,40 +504,59 @@ + type="org.eclipse.core.resources.IFile"> - - - + + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + type="org.eclipse.core.resources.IFile"> - - - + + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - !p.startsWith(".") && !p.getFileName().toString().endsWith(".java"))); boolean isTest = false; try { isTest = sf.getClasspathAttributes().stream().filter(attr -> "gradle_used_by_scope".equals(attr.getName()) && "test".equals(attr.getValue())).findFirst().isPresent(); diff --git a/headless-services/commons/commons-rewrite/pom.xml b/headless-services/commons/commons-rewrite/pom.xml index a7825bffa..006b7ee57 100644 --- a/headless-services/commons/commons-rewrite/pom.xml +++ b/headless-services/commons/commons-rewrite/pom.xml @@ -56,6 +56,16 @@ rewrite-maven ${rewrite-version} + + org.openrewrite + rewrite-groovy + ${rewrite-version} + + + org.openrewrite + rewrite-gradle + ${rewrite-version} + org.openrewrite rewrite-yaml @@ -88,6 +98,48 @@ ${rewrite-spring-version} + + org.openrewrite.gradle.tooling + model + ${rewrite-gradle-tooling-api-version} + + + + org.gradle + gradle-tooling-api + 7.6 + runtime + + + + org.springframework.ide.vscode + commons-maven + ${project.version} + test + + + org.springframework.ide.vscode + commons-gradle + ${project.version} + test + + + org.springframework.ide.vscode + commons-maven + ${project.version} + test + + + + + + + gradle-repo + Gradle Tooling Repo + https://repo.gradle.org/gradle/libs-releases + + + \ No newline at end of file diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/gradle/GradleIJavaProjectParser.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/gradle/GradleIJavaProjectParser.java new file mode 100644 index 000000000..559ea28fc --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/gradle/GradleIJavaProjectParser.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.rewrite.gradle; + +import static org.openrewrite.Tree.randomId; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser.Input; +import org.openrewrite.SourceFile; +import org.openrewrite.gradle.GradleParser; +import org.openrewrite.gradle.marker.GradleProject; +import org.openrewrite.gradle.toolingapi.OpenRewriteModel; +import org.openrewrite.gradle.toolingapi.OpenRewriteModelBuilder; +import org.openrewrite.groovy.GroovyParser; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaParser.Builder; +import org.openrewrite.java.marker.JavaProject; +import org.openrewrite.java.marker.JavaVersion; +import org.openrewrite.marker.BuildTool; +import org.openrewrite.marker.Marker; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.rewrite.java.AbstractJavaProjectParser; + +public class GradleIJavaProjectParser extends AbstractJavaProjectParser { + + public GradleIJavaProjectParser(IJavaProject jp, Builder javaParserBuilder, + Function parserInputProvider) { + super(jp, javaParserBuilder, parserInputProvider); + } + + @Override + protected List getJavaProvenance(SourceFile buildFileAst, Path projectDirectory) { + Optional gradleProject = buildFileAst.getMarkers().findFirst(GradleProject.class); + + String javaRuntimeVersion = System.getProperty("java.runtime.version"); + String javaVendor = System.getProperty("java.vm.vendor"); + String sourceCompatibility = javaRuntimeVersion; + String targetCompatibility = javaRuntimeVersion; + + return Arrays.asList( + new BuildTool(randomId(), BuildTool.Type.Gradle, null), + new JavaVersion(randomId(), javaRuntimeVersion, javaVendor, sourceCompatibility, targetCompatibility), + new JavaProject(randomId(), gradleProject.map(g -> g.getName()).orElse(null), null/*new JavaProject.Publication( + mavenModel.getGroupId(), + mavenModel.getArtifactId(), + mavenModel.getVersion()*/ + ) + ); + } + + @Override + protected List parseBuildFiles(Path projectDir, ExecutionContext ctx) { + OpenRewriteModel openRewriteGradleModel = OpenRewriteModelBuilder.forProjectDirectory(projectDir.toFile(), Paths.get(jp.getProjectBuild().getBuildFile()).toFile()); + GradleProject gradleProject = GradleProject.fromToolingModel(openRewriteGradleModel.gradleProject()); + GradleParser gradleParser = GradleParser.builder().groovyParser(GroovyParser.builder()).build(); + + Path buildFilePath = Paths.get(jp.getProjectBuild().getBuildFile()); + + return ListUtils.map( + gradleParser.parseInputs(() -> + getInputs(Stream.of(buildFilePath)).iterator(), null, ctx), gb -> gb.withMarkers(gb.getMarkers().addIfAbsent(gradleProject)) + ); + } + +} diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/AbstractJavaProjectParser.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/AbstractJavaProjectParser.java new file mode 100644 index 000000000..35879237b --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/AbstractJavaProjectParser.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.rewrite.java; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.openrewrite.Parser; +import org.openrewrite.Parser.Input; +import org.openrewrite.SourceFile; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaParser.Builder; +import org.springframework.ide.vscode.commons.java.IClasspathUtil; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.protocol.java.Classpath; +import org.springframework.ide.vscode.commons.protocol.java.Classpath.CPE; + +public abstract class AbstractJavaProjectParser extends ProjectParser { + + private static String[] NON_JAVA_FILE_TYPES = new String[] { ".properties", ".xml", ".yml", ".yaml", ".factories" }; + + private static String JAVA_FILE_TYPE = ".java"; + + private static Predicate MAIN_JAVA_CPE_FILTER = cpe -> Classpath.isSource(cpe) && cpe.isOwn() && cpe.isJavaContent() && !cpe.isTest(); + + private static Predicate TEST_JAVA_CPE_FILTER = cpe -> Classpath.isSource(cpe) && cpe.isOwn() && cpe.isJavaContent() && cpe.isTest(); + + private static Predicate MAIN_NON_JAVA_CPE_FILTER = cpe -> Classpath.isSource(cpe) && cpe.isOwn() && !cpe.isJavaContent() && !cpe.isTest(); + + private static Predicate TEST_NON_JAVA_CPE_FILTER = cpe -> Classpath.isSource(cpe) && cpe.isOwn() && !cpe.isJavaContent() && cpe.isTest(); + + protected IJavaProject jp; + private Builder javaParserBuilder; + private Function parserInputProvider; + + protected AbstractJavaProjectParser(IJavaProject jp, JavaParser.Builder javaParserBuilder, + Function parserInputProvider) { + this.jp = jp; + this.javaParserBuilder = javaParserBuilder; + this.parserInputProvider = parserInputProvider; + } + + + @Override + protected List getSourceSets(Path projectDir, SourceFile buildFile) { + return List.of( + new SourceSet( + ProjectParser.MAIN, + getSources(MAIN_JAVA_CPE_FILTER, JAVA_FILE_TYPE), + getSources(MAIN_NON_JAVA_CPE_FILTER, NON_JAVA_FILE_TYPES), + IClasspathUtil.getBinaryRoots(jp.getClasspath(), cpe -> !cpe.isTest()).stream().map(f -> f.toPath()).collect(Collectors.toList()) + ), + new SourceSet( + ProjectParser.TEST, + getSources(TEST_JAVA_CPE_FILTER, JAVA_FILE_TYPE), + getSources(TEST_NON_JAVA_CPE_FILTER, NON_JAVA_FILE_TYPES), + IClasspathUtil.getBinaryRoots(jp.getClasspath(), cpe -> !cpe.isTest()).stream().map(f -> f.toPath()).collect(Collectors.toList()) + ) + ); + } + + + private List getSources(Predicate cpeFilter, String... fileTypes) { + BiPredicate predicate = (p, bfa) -> bfa.isRegularFile() + && Arrays.stream(fileTypes).anyMatch(type -> p.getFileName().toString().endsWith(type)); + + try { + return jp.getClasspath().getClasspathEntries().stream().filter(cpeFilter).flatMap(cpe -> { + try { + return Files.find(Paths.get(cpe.getPath()), 999, predicate); + } catch (IOException e) { + return Stream.empty(); + } + }).collect(Collectors.toList()); + } catch (Exception e) { + return Collections.emptyList(); + } + } + + @Override + protected Input createParserInput(Path p) { + Parser.Input in = null; + if (parserInputProvider != null) { + in = parserInputProvider.apply(p); + } + if (in == null) { + return super.createParserInput(p); + } + return in; + } + + + @Override + protected Builder getJavaParserBuilder() { + return javaParserBuilder; + } + +} diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/IJavaProjectParser.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/IJavaProjectParser.java new file mode 100644 index 000000000..0cacfd055 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/IJavaProjectParser.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.rewrite.java; + +import java.util.List; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; +import org.springframework.ide.vscode.commons.java.IJavaProject; + +public interface IJavaProjectParser { + + List parse(IJavaProject project, ExecutionContext ctx); + +} diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ORAstUtils.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ORAstUtils.java index 958d2ae5d..04aba01a5 100644 --- a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ORAstUtils.java +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ORAstUtils.java @@ -18,6 +18,7 @@ import java.nio.channels.ClosedByInterruptException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -52,7 +53,6 @@ import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; -import org.springframework.ide.vscode.commons.rewrite.maven.MavenProjectParser; import org.springframework.ide.vscode.commons.util.ExceptionUtil; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -462,13 +462,13 @@ public class ORAstUtils { public static String getSourceSetName(IJavaProject project, Path sourcePath) { if (IClasspathUtil.getProjectTestJavaSources(project.getClasspath()).anyMatch(f -> sourcePath.startsWith(f.toPath()))) { - return MavenProjectParser.TEST; + return ProjectParser.TEST; } else { - return MavenProjectParser.MAIN; + return ProjectParser.MAIN; } } - public static JavaSourceSet addJavaSourceSet(List sourceFiles, String sourceSetName, List classpath) { + public static JavaSourceSet addJavaSourceSet(List sourceFiles, String sourceSetName, Collection classpath) { JavaSourceSet sourceSet = JavaSourceSet.build(sourceSetName, classpath, null, false); List types = sourceSet.getClasspath(); for (SourceFile sourceFile : sourceFiles) { diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ProjectParser.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ProjectParser.java new file mode 100644 index 000000000..6a0ceee08 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ProjectParser.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.rewrite.java; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.Parser.Input; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J.CompilationUnit; +import org.openrewrite.marker.Marker; +import org.openrewrite.properties.PropertiesParser; +import org.openrewrite.text.PlainTextParser; +import org.openrewrite.xml.XmlParser; +import org.openrewrite.yaml.YamlParser; + +public abstract class ProjectParser { + + public static final String MAIN = "main"; + public static final String TEST = "test"; + + protected static record SourceSet(String name, Collection javaSources, Collection resources, Collection classpath) {}; + + public List parse(Path projectDir, ExecutionContext ctx) { + List buildFiles = parseBuildFiles(projectDir, ctx); + List sources = new ArrayList<>(); + + for (SourceFile buildFile : buildFiles) { + sources.addAll(parseModule(projectDir, buildFile, ctx)); + } + + return sources; + } + + protected Collection parseModule(Path projectDir, SourceFile buildFile, ExecutionContext ctx) { + List sources = new ArrayList<>(); + List projectProvenance = getJavaProvenance(buildFile, projectDir); + sources.add(addProjectProvenance(buildFile, projectProvenance)); + + for (SourceSet ss : getSourceSets(projectDir, buildFile)) { + JavaParser javaParser = getJavaParserBuilder().build(); + + Collection mainClasspath = ss.classpath(); + javaParser.setClasspath(mainClasspath); + + List javaSources = ListUtils.map(javaParser.parseInputs( + () -> getInputs(ss.javaSources.stream()).iterator(), projectDir, ctx), addProvenance(projectProvenance)); + JavaSourceSet javaSourceSet = ORAstUtils.addJavaSourceSet(javaSources, ss.name(), + mainClasspath); + sources.addAll(javaSources); + + List resources = getInputs(ss.resources().stream()).collect(Collectors.toList()); + parseResources(resources, projectDir, sources, projectProvenance, javaSourceSet, ctx); + } + + return sources; + } + + private void parseResources(List resources, Path projectDirectory, List sourceFiles, List projectProvenance, JavaSourceSet sourceSet, ExecutionContext ctx) { + List provenance = new ArrayList<>(projectProvenance); + provenance.add(sourceSet); + + sourceFiles.addAll(ListUtils.map(new XmlParser().parseInputs( + resources.stream() + .filter(p -> p.getPath().getFileName().toString().endsWith(".xml") || + p.getPath().getFileName().toString().endsWith(".wsdl") || + p.getPath().getFileName().toString().endsWith(".xhtml") || + p.getPath().getFileName().toString().endsWith(".xsd") || + p.getPath().getFileName().toString().endsWith(".xsl") || + p.getPath().getFileName().toString().endsWith(".xslt")) + .collect(Collectors.toList()), + projectDirectory, + ctx + ), addProvenance(provenance))); + + sourceFiles.addAll(ListUtils.map(new YamlParser().parseInputs( + resources.stream() + .filter(p -> p.getPath().getFileName().toString().endsWith(".yml") || p.getPath().getFileName().toString().endsWith(".yaml")) + .collect(Collectors.toList()), + projectDirectory, + ctx + ), addProvenance(provenance))); + + sourceFiles.addAll(ListUtils.map(new PropertiesParser().parseInputs( + resources.stream() + .filter(p -> p.getPath().getFileName().toString().endsWith(".properties")) + .collect(Collectors.toList()), + projectDirectory, + ctx + ), addProvenance(provenance))); + + sourceFiles.addAll(ListUtils.map(new PlainTextParser().parseInputs( + resources.stream() + .filter(p -> p.getPath().getFileName().toString().endsWith(".factories")) + .collect(Collectors.toList()), + projectDirectory, + ctx + ), addProvenance(provenance))); + } + + + private S addProjectProvenance(S s, List projectProvenance) { + for (Marker marker : projectProvenance) { + s = s.withMarkers(s.getMarkers().addIfAbsent(marker)); + } + return s; + } + + private UnaryOperator addProvenance(List projectProvenance) { + return s -> { + if (projectProvenance != null) { + s = addProjectProvenance(s, projectProvenance); + } + return s; + }; + } + + protected JavaParser.Builder getJavaParserBuilder() { + return JavaParser.fromJavaVersion(); + } + + protected final Stream getInputs(Stream files) { + return files.map(p -> + new Parser.Input(p, () -> { + try { + return Files.newInputStream(p); + } catch (IOException e) { + return new ByteArrayInputStream(new byte[0]); + } + }) + ); + } + + protected Parser.Input createParserInput(Path p) { + return new Parser.Input(p, () -> { + try { + return Files.newInputStream(p); + } catch (IOException e) { + return new ByteArrayInputStream(new byte[0]); + } + }); + } + + + abstract protected List getJavaProvenance(SourceFile buildFileAst, Path projectDirectory); + + abstract protected List parseBuildFiles(Path projectDir, ExecutionContext ctx); + + abstract protected Collection getSourceSets(Path projectDir, SourceFile buildFile); + + +} diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenIJavaProjectParser.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenIJavaProjectParser.java new file mode 100644 index 000000000..7ef107dd9 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenIJavaProjectParser.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.rewrite.maven; + +import static org.openrewrite.Tree.randomId; + +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser.Input; +import org.openrewrite.SourceFile; +import org.openrewrite.java.JavaParser.Builder; +import org.openrewrite.java.marker.JavaProject; +import org.openrewrite.java.marker.JavaVersion; +import org.openrewrite.marker.BuildTool; +import org.openrewrite.marker.Marker; +import org.openrewrite.maven.MavenParser; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.maven.tree.ResolvedPom; +import org.openrewrite.xml.tree.Xml; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.rewrite.java.AbstractJavaProjectParser; + +public class MavenIJavaProjectParser extends AbstractJavaProjectParser { + + private static final Logger logger = LoggerFactory.getLogger(MavenIJavaProjectParser.class); + + private static final Pattern mavenWrapperVersionPattern = Pattern.compile(".*apache-maven/(.*?)/.*"); + + private MavenParser.Builder mavenParserBuilder; + + public MavenIJavaProjectParser(IJavaProject jp, Builder javaParserBuilder, + Function parserInputProvider, MavenParser.Builder mavenParserBuilder) { + super(jp, javaParserBuilder, parserInputProvider); + this.mavenParserBuilder = mavenParserBuilder; + } + + protected List getJavaProvenance(SourceFile maven, Path projectDirectory) { + ResolvedPom mavenModel = getModel((Xml.Document) maven); + String javaRuntimeVersion = System.getProperty("java.runtime.version"); + String javaVendor = System.getProperty("java.vm.vendor"); + String sourceCompatibility = javaRuntimeVersion; + String targetCompatibility = javaRuntimeVersion; + String propertiesSourceCompatibility = mavenModel.getValue(mavenModel.getValue("maven.compiler.source")); + if (propertiesSourceCompatibility != null) { + sourceCompatibility = propertiesSourceCompatibility; + } + String propertiesTargetCompatibility = mavenModel.getValue(mavenModel.getValue("maven.compiler.target")); + if (propertiesTargetCompatibility != null) { + targetCompatibility = propertiesTargetCompatibility; + } + + Path wrapperPropertiesPath = projectDirectory.resolve(".mvn/wrapper/maven-wrapper.properties"); + String mavenVersion = "3.6"; + if (Files.exists(wrapperPropertiesPath)) { + try { + Properties wrapperProperties = new Properties(); + wrapperProperties.load(new FileReader(wrapperPropertiesPath.toFile())); + String distributionUrl = (String) wrapperProperties.get("distributionUrl"); + if (distributionUrl != null) { + Matcher wrapperVersionMatcher = mavenWrapperVersionPattern.matcher(distributionUrl); + if (wrapperVersionMatcher.matches()) { + mavenVersion = wrapperVersionMatcher.group(1); + } + } + } catch (IOException e) { + logger.error("", e); + } + } + + return Arrays.asList( + new BuildTool(randomId(), BuildTool.Type.Maven, mavenVersion), + new JavaVersion(randomId(), javaRuntimeVersion, javaVendor, sourceCompatibility, targetCompatibility), + new JavaProject(randomId(), mavenModel.getRequested().getName(), new JavaProject.Publication( + mavenModel.getGroupId(), + mavenModel.getArtifactId(), + mavenModel.getVersion() + )) + ); + } + + @Override + protected List parseBuildFiles(Path projectDir, ExecutionContext ctx) { + MavenParser mavenParser = mavenParserBuilder.build(); + return mavenParser.parseInputs(() -> getInputs(Stream.of(Paths.get(jp.getProjectBuild().getBuildFile()))).iterator(), projectDir, ctx); + } + + private static ResolvedPom getModel(Xml.Document maven) { + MavenResolutionResult pom = getResolvedPom(maven); + return pom == null ? null : pom.getPom(); + } + + private static MavenResolutionResult getResolvedPom(Xml.Document maven) { + return maven.getMarkers().findFirst(MavenResolutionResult.class).orElse(null); + } + + +} diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenProjectParser.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenProjectParser.java deleted file mode 100644 index ba325638d..000000000 --- a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenProjectParser.java +++ /dev/null @@ -1,389 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 VMware, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VMware, Inc. - initial API and implementation - *******************************************************************************/ -package org.springframework.ide.vscode.commons.rewrite.maven; - -import static org.openrewrite.Tree.randomId; - -import java.io.ByteArrayInputStream; -import java.io.FileReader; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.function.BiPredicate; -import java.util.function.Function; -import java.util.function.UnaryOperator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Parser; -import org.openrewrite.SourceFile; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.java.JavaParser; -import org.openrewrite.java.marker.JavaProject; -import org.openrewrite.java.marker.JavaSourceSet; -import org.openrewrite.java.marker.JavaVersion; -import org.openrewrite.java.tree.J.CompilationUnit; -import org.openrewrite.marker.BuildTool; -import org.openrewrite.marker.Marker; -import org.openrewrite.maven.MavenParser; -import org.openrewrite.maven.tree.Dependency; -import org.openrewrite.maven.tree.MavenResolutionResult; -import org.openrewrite.maven.tree.Pom; -import org.openrewrite.maven.tree.ResolvedPom; -import org.openrewrite.properties.PropertiesParser; -import org.openrewrite.text.PlainTextParser; -import org.openrewrite.xml.XmlParser; -import org.openrewrite.xml.tree.Xml; -import org.openrewrite.xml.tree.Xml.Document; -import org.openrewrite.yaml.YamlParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils; - -/** - * Parse a Maven project on disk into a list of {@link org.openrewrite.SourceFile} including - * Maven, Java, YAML, properties, and XML AST representations of sources and resources found. - */ -public class MavenProjectParser { - - public static final String TEST = "test"; - public static final String MAIN = "main"; - private static final Pattern mavenWrapperVersionPattern = Pattern.compile(".*apache-maven/(.*?)/.*"); - private static final Logger logger = LoggerFactory.getLogger(MavenProjectParser.class); - - private final MavenParser mavenParser; - private final JavaParser.Builder javaParserBuilder; - private final ExecutionContext ctx; - private final Function parserInputProvider; - - public MavenProjectParser(MavenParser.Builder mavenParserBuilder, - JavaParser.Builder javaParserBuilder, - ExecutionContext ctx, - Function parserInputProvider) { - this.mavenParser = mavenParserBuilder.build(); - this.javaParserBuilder = javaParserBuilder; - this.ctx = ctx; - this.parserInputProvider = parserInputProvider; - } - - /** - * Given a root path to a maven project, this parser will parse the maven project (including submodules) - * and return a list of ALL source files for all maven modules under the root path. - *
-     * Notes About Provenance Information:
-     *
-     * There are always three markers applied to each source file and there can potentially be up to five provenance
-     * markers in total:
-     *
-     * BuildTool     - What build tool was used to compile the source file (This will always be Maven)
-     * JavaVersion   - What Java version/vendor was used when compiling the source file.
-     * JavaProject   - For each maven module/sub-module, the same JavaProject will be associated with ALL source files
-     *                 belonging to that module.
-     *
-     * Optional:
-     *
-     * GitProvenance - If the entire project exists in the context of a git repository, all source files (for all modules) will have the same GitProvenance.
-     * JavaSourceSet - All Java source files and all resource files that exist in src/main or src/test will have a JavaSourceSet marker assigned to them.
-     *
-     * 
- * @param projectDirectory A path to the root folder containing a meven project. - * @return A list of source files that have been parsed from the root folder - */ - public List parse(Path projectDirectory, List dependencies) { - List mavens = mavenParser.parseInputs(getMavenPoms(projectDirectory, ctx, parserInputProvider), projectDirectory, ctx); - List sorted = sort(mavens); - - // Filter out pom files inside target folders. (Naive implementation.) - mavens = sorted.stream().filter(m -> !isInsideBuildFolderOfOtherMavenProjects(sorted, m)).collect(Collectors.toList()); - - JavaParser javaParser = javaParserBuilder.build(); - - logger.info("The order in which projects are being parsed is:"); - for (Xml.Document maven : mavens) { - logger.info(" {}:{}", getModel(maven).getGroupId(), getModel(maven).getArtifactId()); - } - - List sourceFiles = new ArrayList<>(); - for (Xml.Document maven : mavens) { - List projectProvenance = getJavaProvenance(maven, projectDirectory); - sourceFiles.add(addProjectProvenance(maven, projectProvenance)); - -// List dependencies = downloadArtifacts(getResolvedPom(maven).getDependencies().get(Scope.Compile)); - javaParser.setClasspath(dependencies); - List mainJavaSources = ListUtils.map(javaParser.parseInputs( - getJavaSources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, ctx), addProvenance(projectProvenance)); - JavaSourceSet mainSourceSet = ORAstUtils.addJavaSourceSet(mainJavaSources, MAIN, dependencies); - sourceFiles.addAll(mainJavaSources); - //Resources in the src/main should also have the main source set attached to them. - parseResources(getResources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, sourceFiles, projectProvenance, mainSourceSet); - -// List testDependencies = downloadArtifacts(maven.getModel().getDependencies(Scope.Test)); -// javaParser.setClasspath(testDependencies); - List testJavaSources = ListUtils.map(javaParser.parseInputs( - getTestJavaSources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, ctx), addProvenance(projectProvenance)); - JavaSourceSet testSourceSet = ORAstUtils.addJavaSourceSet(testJavaSources, TEST, dependencies); - sourceFiles.addAll(testJavaSources); - //Resources in the src/test should also have the test source set attached to them. - parseResources(getTestResources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, sourceFiles, projectProvenance, testSourceSet); - } - - return sourceFiles; - } - - private List getJavaProvenance(Xml.Document maven, Path projectDirectory) { - ResolvedPom mavenModel = getModel(maven); - String javaRuntimeVersion = System.getProperty("java.runtime.version"); - String javaVendor = System.getProperty("java.vm.vendor"); - String sourceCompatibility = javaRuntimeVersion; - String targetCompatibility = javaRuntimeVersion; - String propertiesSourceCompatibility = mavenModel.getValue(mavenModel.getValue("maven.compiler.source")); - if (propertiesSourceCompatibility != null) { - sourceCompatibility = propertiesSourceCompatibility; - } - String propertiesTargetCompatibility = mavenModel.getValue(mavenModel.getValue("maven.compiler.target")); - if (propertiesTargetCompatibility != null) { - targetCompatibility = propertiesTargetCompatibility; - } - - Path wrapperPropertiesPath = projectDirectory.resolve(".mvn/wrapper/maven-wrapper.properties"); - String mavenVersion = "3.6"; - if (Files.exists(wrapperPropertiesPath)) { - try { - Properties wrapperProperties = new Properties(); - wrapperProperties.load(new FileReader(wrapperPropertiesPath.toFile())); - String distributionUrl = (String) wrapperProperties.get("distributionUrl"); - if (distributionUrl != null) { - Matcher wrapperVersionMatcher = mavenWrapperVersionPattern.matcher(distributionUrl); - if (wrapperVersionMatcher.matches()) { - mavenVersion = wrapperVersionMatcher.group(1); - } - } - } catch (IOException e) { - ctx.getOnError().accept(e); - } - } - - return Arrays.asList( - new BuildTool(randomId(), BuildTool.Type.Maven, mavenVersion), - new JavaVersion(randomId(), javaRuntimeVersion, javaVendor, sourceCompatibility, targetCompatibility), - new JavaProject(randomId(), mavenModel.getRequested().getName(), new JavaProject.Publication( - mavenModel.getGroupId(), - mavenModel.getArtifactId(), - mavenModel.getVersion() - )) - ); - } - - private void parseResources(List resources, Path projectDirectory, List sourceFiles, List projectProvenance, JavaSourceSet sourceSet) { - List provenance = new ArrayList<>(projectProvenance); - provenance.add(sourceSet); - - sourceFiles.addAll(ListUtils.map(new XmlParser().parseInputs( - resources.stream() - .filter(p -> p.getPath().getFileName().toString().endsWith(".xml") || - p.getPath().getFileName().toString().endsWith(".wsdl") || - p.getPath().getFileName().toString().endsWith(".xhtml") || - p.getPath().getFileName().toString().endsWith(".xsd") || - p.getPath().getFileName().toString().endsWith(".xsl") || - p.getPath().getFileName().toString().endsWith(".xslt")) - .collect(Collectors.toList()), - projectDirectory, - ctx - ), addProvenance(provenance))); - - sourceFiles.addAll(ListUtils.map(new YamlParser().parseInputs( - resources.stream() - .filter(p -> p.getPath().getFileName().toString().endsWith(".yml") || p.getPath().getFileName().toString().endsWith(".yaml")) - .collect(Collectors.toList()), - projectDirectory, - ctx - ), addProvenance(provenance))); - - sourceFiles.addAll(ListUtils.map(new PropertiesParser().parseInputs( - resources.stream() - .filter(p -> p.getPath().getFileName().toString().endsWith(".properties")) - .collect(Collectors.toList()), - projectDirectory, - ctx - ), addProvenance(provenance))); - - sourceFiles.addAll(ListUtils.map(new PlainTextParser().parseInputs( - resources.stream() - .filter(p -> p.getPath().getFileName().toString().endsWith(".factories")) - .collect(Collectors.toList()), - projectDirectory, - ctx - ), addProvenance(provenance))); - } - - private S addProjectProvenance(S s, List projectProvenance) { - for (Marker marker : projectProvenance) { - s = s.withMarkers(s.getMarkers().addIfAbsent(marker)); - } - return s; - } - - private UnaryOperator addProvenance(List projectProvenance) { - return s -> { - s = addProjectProvenance(s, projectProvenance); - return s; - }; - } - -// private List downloadArtifacts(Set dependencies) { -// return dependencies.stream() -// .filter(d -> d.getRepository() != null) -// .map(artifactDownloader::downloadArtifact) -// .filter(Objects::nonNull) -// .collect(Collectors.toList()); -// } - - public static List sort(List mavens) { - // the value is the set of maven projects that depend on the key - Map> byDependedOn = new HashMap<>(); - - for (Xml.Document maven : mavens) { - byDependedOn.computeIfAbsent(maven, m -> new HashSet<>()); - for (Dependency dependency : getModel(maven).getRequested().getDependencies()) { - for (Xml.Document test : mavens) { - if (getModel(test).getGroupId().equals(dependency.getGroupId()) && - getModel(test).getArtifactId().equals(dependency.getArtifactId())) { - byDependedOn.computeIfAbsent(maven, m -> new HashSet<>()).add(test); - } - } - } - } - - List sorted = new ArrayList<>(mavens.size()); - next: - while (!byDependedOn.isEmpty()) { - for (Map.Entry> mavenAndDependencies : byDependedOn.entrySet()) { - if (mavenAndDependencies.getValue().isEmpty()) { - Xml.Document maven = mavenAndDependencies.getKey(); - byDependedOn.remove(maven); - sorted.add(maven); - for (Set dependencies : byDependedOn.values()) { - dependencies.remove(maven); - } - continue next; - } - } - } - - return sorted; - } - - private static boolean isInsideBuildFolderOfOtherMavenProjects(List all, Xml.Document current) { - return all.stream().filter(m -> { - if (m != current) { - Path pomPath = m.getSourcePath(); - return current.getSourcePath().startsWith((pomPath.getParent() == null ? Paths.get("") : pomPath.getParent()) .resolve("target")); - } - return false; - }).findFirst().isPresent(); - } - - private static List getSources(Path srcDir, ExecutionContext ctx, Function parserInputProvider, String... fileTypes) { - if (!srcDir.toFile().exists()) { - return List.of(); - } - - BiPredicate predicate = (p, bfa) -> - bfa.isRegularFile() && Arrays.stream(fileTypes).anyMatch(type -> p.getFileName().toString().endsWith(type)); - try { - return Files.find(srcDir, 999, predicate).map(p -> { - Parser.Input in = null; - if (parserInputProvider != null) { - in = parserInputProvider.apply(p); - } - if (in == null) { - in = new Parser.Input(p, () -> { - try { - return Files.newInputStream(p); - } catch (IOException e) { - return new ByteArrayInputStream(new byte[0]); - } - }); - } - return in; - }).collect(Collectors.toList()); - } catch (IOException e) { - ctx.getOnError().accept(e); - return List.of(); - } - } - - public static List getMavenPoms(Path projectDir, ExecutionContext ctx, - Function parserInputProvider) { - return getSources(projectDir, ctx, parserInputProvider, "pom.xml").stream().filter(p -> { - Path relativeToProject = projectDir.relativize(p.getPath()); - String relativePathStr = relativeToProject.toString(); - return relativeToProject.getFileName().toString().equals("pom.xml") - && !relativePathStr.contains("/src/") && !relativePathStr.startsWith("src/") - && !relativePathStr.contains("/bin/") && !relativePathStr.startsWith("bin/") - && !relativePathStr.contains("/target/") && !relativePathStr.startsWith("target/"); - }).collect(Collectors.toList()); - } - - private static ResolvedPom getModel(Xml.Document maven) { - MavenResolutionResult pom = getResolvedPom(maven); - return pom == null ? null : pom.getPom(); - } - - private static MavenResolutionResult getResolvedPom(Xml.Document maven) { - return maven.getMarkers().findFirst(MavenResolutionResult.class).orElse(null); - } - - private static List getJavaSources(Pom pom, Path projectDir, ExecutionContext ctx, Function parserInputProvider) { - if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) { - return List.of(); - } - return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "main", "java")), - ctx, parserInputProvider, ".java"); - } - - private static List getTestJavaSources(Pom pom, Path projectDir, ExecutionContext ctx, Function parserInputProvider) { - if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) { - return List.of(); - } - return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "test", "java")), - ctx, parserInputProvider, ".java"); - } - - private static List getResources(Pom pom, Path projectDir, ExecutionContext ctx, Function parserInputProvider) { - if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) { - return List.of(); - } - return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "main", "resources")), - ctx, parserInputProvider, ".properties", ".xml", ".yml", ".yaml", ".factories"); - } - - private static List getTestResources(Pom pom, Path projectDir, ExecutionContext ctx, Function parserInputProvider) { - if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) { - return List.of(); - } - return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "test", "resources")), - ctx, parserInputProvider, ".properties", ".xml", ".yml", ".yaml"); - } - - -} \ No newline at end of file diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/gradle/GradleIJavaProjectParserTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/gradle/GradleIJavaProjectParserTest.java new file mode 100644 index 000000000..4682a25d6 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/gradle/GradleIJavaProjectParserTest.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.rewrite.gradle; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.SourceFile; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaSourceFile; +import org.openrewrite.properties.tree.Properties; +import org.openrewrite.text.PlainText; +import org.openrewrite.yaml.tree.Yaml; +import org.springframework.ide.vscode.commons.gradle.GradleCore; +import org.springframework.ide.vscode.commons.gradle.GradleJavaProject; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.rewrite.java.ProjectParser; + +public class GradleIJavaProjectParserTest { + + @Test + void testSingleGroovy() throws Exception { + URL resource = getClass().getResource("/test-projects/example-gradle-groovy"); + Path testProjectPath = Paths.get(resource.toURI()); + + IJavaProject jp = GradleJavaProject.create(null, GradleCore.getDefault(), testProjectPath.resolve("build.gradle").toFile(), null); + + GradleIJavaProjectParser parser = new GradleIJavaProjectParser(jp, JavaParser.fromJavaVersion(), null); + + List sources = parser.parse(Paths.get(jp.getLocationUri()), new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + })); + + assertEquals(9, sources.size()); + + // java sources + assertEquals(2, sources.stream().filter(J.CompilationUnit.class::isInstance).collect(Collectors.toList()).size()); + + // java sources from main + assertEquals(1, sources.stream().filter(JavaSourceFile.class::isInstance).map(JavaSourceFile.class::cast).filter(j -> { + String sourceSetName = j.getMarkers().findFirst(JavaSourceSet.class).map(js -> js.getName()).orElse(null); + return ProjectParser.MAIN.equals(sourceSetName); + }).collect(Collectors.toList()).size()); + + // java sources from test + assertEquals(1, sources.stream().filter(JavaSourceFile.class::isInstance).map(JavaSourceFile.class::cast).filter(j -> { + String sourceSetName = j.getMarkers().findFirst(JavaSourceSet.class).map(js -> js.getName()).orElse(null); + return ProjectParser.TEST.equals(sourceSetName); + }).collect(Collectors.toList()).size()); + + // properties files + assertEquals(1, sources.stream().filter(Properties.File.class::isInstance).collect(Collectors.toList()).size()); + + // application properties + assertEquals(1, sources.stream().filter(Properties.File.class::isInstance).filter(f -> f.getSourcePath().getFileName().toString().equals("application.properties")).collect(Collectors.toList()).size()); + + // yaml files + assertEquals(2, sources.stream().filter(Yaml.Documents.class::isInstance).collect(Collectors.toList()).size()); + + // application yaml + assertEquals(2, sources.stream().filter(Yaml.Documents.class::isInstance).filter(f -> f.getSourcePath().getFileName().toString().equals("application.yml")).collect(Collectors.toList()).size()); + + // plain text files + assertEquals(3, sources.stream().filter(PlainText.class::isInstance).collect(Collectors.toList()).size()); + + // .factories files + assertEquals(3, sources.stream().filter(PlainText.class::isInstance).filter(f -> f.getSourcePath().getFileName().toString().endsWith(".factories")).collect(Collectors.toList()).size()); + + + } + +} diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenProjectParserTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenIJavaProjectParserTest.java similarity index 67% rename from headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenProjectParserTest.java rename to headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenIJavaProjectParserTest.java index 5db1b4d4d..6b9aba4ec 100644 --- a/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenProjectParserTest.java +++ b/headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/maven/MavenIJavaProjectParserTest.java @@ -12,10 +12,8 @@ package org.springframework.ide.vscode.commons.rewrite.maven; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -29,25 +27,41 @@ import org.openrewrite.maven.MavenParser; import org.openrewrite.properties.tree.Properties; import org.openrewrite.text.PlainText; import org.openrewrite.yaml.tree.Yaml; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.javadoc.JavaDocProviders; +import org.springframework.ide.vscode.commons.maven.MavenBuilder; +import org.springframework.ide.vscode.commons.maven.MavenCore; +import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; +import org.springframework.ide.vscode.commons.rewrite.java.ProjectParser; + +public class MavenIJavaProjectParserTest { + + private static IJavaProject createProject(String name) throws Exception { + Path projectPath = Paths.get(MavenIJavaProjectParserTest.class.getResource("/test-projects/" + name).toURI()); + + MavenBuilder.newBuilder(projectPath).clean().pack().skipTests().execute(); + return MavenJavaProject.create(null, MavenCore.getDefault(), + projectPath.resolve(MavenCore.POM_XML).toFile(), (uri, cpe) -> JavaDocProviders.createFor(cpe)); + } -public class MavenProjectParserTest { @Test void parseResources() throws Exception { - URL resource = getClass().getResource("/test-projects/test-maven-project-parser"); - Path testProjectPath = Paths.get(resource.toURI()); + IJavaProject jp = createProject("test-maven-project-parser"); + Path testProjectPath = Paths.get(jp.getLocationUri()); + MavenParser.Builder mavenParserBuilder = MavenParser.builder() .mavenConfig(testProjectPath.resolve(".mvn/maven.config")); - - MavenProjectParser parser = new MavenProjectParser(mavenParserBuilder, JavaParser.fromJavaVersion(), new InMemoryExecutionContext(t -> { + + MavenIJavaProjectParser parser = new MavenIJavaProjectParser(jp, JavaParser.fromJavaVersion(), null, mavenParserBuilder); + + List sources = parser.parse(testProjectPath, new InMemoryExecutionContext(t -> { if (t instanceof Error) { throw new RuntimeException(t); }; - }), null); + })); - List sources = parser.parse(testProjectPath, Collections.emptyList()); - - assertEquals(12, sources.size()); + assertEquals(13, sources.size()); // java sources assertEquals(6, sources.stream().filter(JavaSourceFile.class::isInstance).collect(Collectors.toList()).size()); @@ -55,13 +69,13 @@ public class MavenProjectParserTest { // java sources from main assertEquals(5, sources.stream().filter(JavaSourceFile.class::isInstance).map(JavaSourceFile.class::cast).filter(j -> { String sourceSetName = j.getMarkers().findFirst(JavaSourceSet.class).map(js -> js.getName()).orElse(null); - return MavenProjectParser.MAIN.equals(sourceSetName); + return ProjectParser.MAIN.equals(sourceSetName); }).collect(Collectors.toList()).size()); // java sources from test assertEquals(1, sources.stream().filter(JavaSourceFile.class::isInstance).map(JavaSourceFile.class::cast).filter(j -> { String sourceSetName = j.getMarkers().findFirst(JavaSourceSet.class).map(js -> js.getName()).orElse(null); - return MavenProjectParser.TEST.equals(sourceSetName); + return ProjectParser.TEST.equals(sourceSetName); }).collect(Collectors.toList()).size()); // properties files @@ -77,10 +91,10 @@ public class MavenProjectParserTest { assertEquals(2, sources.stream().filter(Yaml.Documents.class::isInstance).filter(f -> f.getSourcePath().getFileName().toString().equals("application.yml")).collect(Collectors.toList()).size()); // plain text files - assertEquals(2, sources.stream().filter(PlainText.class::isInstance).collect(Collectors.toList()).size()); + assertEquals(3, sources.stream().filter(PlainText.class::isInstance).collect(Collectors.toList()).size()); // .factories files - assertEquals(2, sources.stream().filter(PlainText.class::isInstance).filter(f -> f.getSourcePath().getFileName().toString().endsWith(".factories")).collect(Collectors.toList()).size()); + assertEquals(3, sources.stream().filter(PlainText.class::isInstance).filter(f -> f.getSourcePath().getFileName().toString().endsWith(".factories")).collect(Collectors.toList()).size()); } diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/.gitignore b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/build.gradle b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/build.gradle new file mode 100644 index 000000000..d1344e837 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.0.7' + id 'io.spring.dependency-management' version '1.1.0' +} + +group = 'com.example' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-web' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradle/wrapper/gradle-wrapper.jar b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..249e5832f Binary files /dev/null and b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradle/wrapper/gradle-wrapper.jar differ diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradle/wrapper/gradle-wrapper.properties b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..774fae876 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradlew b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradlew new file mode 100644 index 000000000..a69d9cb6c --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradlew.bat b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradlew.bat new file mode 100644 index 000000000..53a6b238d --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/settings.gradle b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/settings.gradle new file mode 100644 index 000000000..094e8e578 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'example-gradle-groovy' diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/java/com/example/demo/ExampleGradleGroovyApplication.java b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/java/com/example/demo/ExampleGradleGroovyApplication.java new file mode 100644 index 000000000..50d1d663e --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/java/com/example/demo/ExampleGradleGroovyApplication.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ExampleGradleGroovyApplication { + + public static void main(String[] args) { + SpringApplication.run(ExampleGradleGroovyApplication.class, args); + } + +} diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/application.properties b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/application.properties new file mode 100644 index 000000000..73b813d27 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/application.properties @@ -0,0 +1,4 @@ +test-map.test-list-object.string-list[0]=not-a-color +test-map.test-list-object.string-list[1]=RED +test-map.test-list-object.string-list[2]=GREEN +test-map.some-key.list[0]=something diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/application.yml b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/application.yml new file mode 100644 index 000000000..5697ab735 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 6574 \ No newline at end of file diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/more.factories b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/more.factories new file mode 100644 index 000000000..e69de29bb diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/spring.factories b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/main/resources/spring.factories new file mode 100644 index 000000000..e69de29bb diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/java/com/example/demo/ExampleGradleGroovyApplicationTests.java b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/java/com/example/demo/ExampleGradleGroovyApplicationTests.java new file mode 100644 index 000000000..ca0135b8c --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/java/com/example/demo/ExampleGradleGroovyApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ExampleGradleGroovyApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/resources/application.yml b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/resources/application.yml new file mode 100644 index 000000000..57d009930 --- /dev/null +++ b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 3243 \ No newline at end of file diff --git a/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/resources/spring.factories b/headless-services/commons/commons-rewrite/src/test/resources/test-projects/example-gradle-groovy/src/test/resources/spring.factories new file mode 100644 index 000000000..e69de29bb diff --git a/headless-services/commons/pom.xml b/headless-services/commons/pom.xml index e1ec1e3bf..5ddfc1760 100644 --- a/headless-services/commons/pom.xml +++ b/headless-services/commons/pom.xml @@ -115,6 +115,7 @@ 7.41.0-SNAPSHOT 4.37.0-SNAPSHOT + 0.9.0-SNAPSHOT true vmware diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java index fb31f0f4e..1f4b7cf07 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java @@ -11,7 +11,6 @@ package org.springframework.ide.vscode.boot.java.rewrite; import java.io.ByteArrayInputStream; -import java.io.File; import java.io.FileInputStream; import java.net.URL; import java.net.URLClassLoader; @@ -33,7 +32,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.TextDocumentIdentifier; @@ -59,19 +57,20 @@ import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.ide.vscode.boot.app.BootJavaConfig; -import org.springframework.ide.vscode.commons.java.IClasspath; -import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.IndefiniteProgressTask; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.ListenerList; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.protocol.java.ProjectBuild; import org.springframework.ide.vscode.commons.rewrite.LoadUtils; import org.springframework.ide.vscode.commons.rewrite.LoadUtils.DurationTypeConverter; import org.springframework.ide.vscode.commons.rewrite.ORDocUtils; import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor; import org.springframework.ide.vscode.commons.rewrite.config.StsEnvironment; -import org.springframework.ide.vscode.commons.rewrite.maven.MavenProjectParser; +import org.springframework.ide.vscode.commons.rewrite.gradle.GradleIJavaProjectParser; +import org.springframework.ide.vscode.commons.rewrite.java.ProjectParser; +import org.springframework.ide.vscode.commons.rewrite.maven.MavenIJavaProjectParser; import org.springframework.ide.vscode.commons.util.text.TextDocument; import com.google.gson.Gson; @@ -417,15 +416,15 @@ public class RewriteRecipeRepository implements ApplicationContextAware { private Optional computeWorkspaceEdit(Recipe r, IJavaProject project, IndefiniteProgressTask progressTask) { Path absoluteProjectDir = Paths.get(project.getLocationUri()); progressTask.progressEvent("Parsing files..."); - MavenProjectParser projectParser = createRewriteMavenParser(absoluteProjectDir, - new InMemoryExecutionContext(), p -> { + ProjectParser projectParser = createRewriteProjectParser(project, + p -> { TextDocument doc = server.getTextDocumentService().getLatestSnapshot(p.toUri().toASCIIString()); if (doc != null) { return new Parser.Input(p, () -> new ByteArrayInputStream(doc.get().getBytes())); } return null; }); - List sources = projectParser.parse(absoluteProjectDir, getClasspathEntries(project)); + List sources = projectParser.parse(absoluteProjectDir, new InMemoryExecutionContext()); progressTask.progressEvent("Computing changes..."); RecipeRun reciperun = r.run(sources, new InMemoryExecutionContext(e -> log.error("Recipe execution failed", e))); List results = reciperun.getResults(); @@ -447,32 +446,20 @@ public class RewriteRecipeRepository implements ApplicationContextAware { return Collections.emptyList(); } - private static MavenProjectParser createRewriteMavenParser(Path absoluteProjectDir, ExecutionContext context, Function inputProvider) { - MavenParser.Builder mavenParserBuilder = MavenParser.builder() - .mavenConfig(absoluteProjectDir.resolve(".mvn/maven.config")); - - MavenProjectParser mavenProjectParser = new MavenProjectParser( - mavenParserBuilder, - JavaParser.fromJavaVersion(), - context, - inputProvider - ); - return mavenProjectParser; + private static ProjectParser createRewriteProjectParser(IJavaProject jp, Function inputProvider) { + switch (jp.getProjectBuild().getType()) { + case ProjectBuild.MAVEN_PROJECT_TYPE: + Path absoluteProjectDir = Paths.get(jp.getLocationUri()).toAbsolutePath(); + MavenParser.Builder mavenParserBuilder = MavenParser.builder() + .mavenConfig(absoluteProjectDir.resolve(".mvn/maven.config")); + return new MavenIJavaProjectParser(jp, JavaParser.fromJavaVersion(), inputProvider, mavenParserBuilder); + case ProjectBuild.GRADLE_PROJECT_TYPE: + return new GradleIJavaProjectParser(jp, JavaParser.fromJavaVersion(), inputProvider); + default: + throw new IllegalStateException("The project is neither Maven nor Gradle!"); + } } - private static List getClasspathEntries(IJavaProject project) { - if (project == null) { - return List.of(); - } else { - IClasspath classpath = project.getClasspath(); - Stream classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream(); - return classpathEntries - .filter(file -> file.exists()) - .filter(file -> file.getName().endsWith(".jar")) - .map(file -> file.getAbsoluteFile().toPath()).collect(Collectors.toList()); - } - } - public void onRecipesLoaded(Consumer l) { loadListeners.add(l); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java index 833e7eefb..c2b9d04aa 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java @@ -54,7 +54,7 @@ import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker; import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; import org.springframework.ide.vscode.commons.rewrite.java.JavaMarkerVisitor; import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils; -import org.springframework.ide.vscode.commons.rewrite.maven.MavenProjectParser; +import org.springframework.ide.vscode.commons.rewrite.java.ProjectParser; import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -165,8 +165,8 @@ public class RewriteReconciler implements JavaReconciler { // Pass in source sets created from classpath. (Perhaps it is a good idea to have separate classpath and parsers for test and main, TBD) // Perhaps it is even better to create empty classpath java source sets as reconcile step seem to only need name of the java source set // Usually java source set classpath is required to figure out how to organize imports for sources - JavaSourceSet mainJavaSourceSet = JavaSourceSet.build(MavenProjectParser.MAIN, classpath, null, false); - JavaSourceSet testJavaSourceSet = new JavaSourceSet(Tree.randomId(), MavenProjectParser.TEST, mainJavaSourceSet.getClasspath()); + JavaSourceSet mainJavaSourceSet = JavaSourceSet.build(ProjectParser.MAIN, classpath, null, false); + JavaSourceSet testJavaSourceSet = new JavaSourceSet(Tree.randomId(), ProjectParser.TEST, mainJavaSourceSet.getClasspath()); allProblems.putAll(doReconcile(project, mainSources, javaParser, mainJavaSourceSet, incrementProgress)); allProblems.putAll(doReconcile(project, testSources, javaParser, testJavaSourceSet, incrementProgress)); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AutowiredFieldIntoConstructorParameterCodeAction.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AutowiredFieldIntoConstructorParameterCodeAction.java index 89d96fec8..b6ec83263 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AutowiredFieldIntoConstructorParameterCodeAction.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AutowiredFieldIntoConstructorParameterCodeAction.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 VMware, Inc. + * Copyright (c) 2022, 2023 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -43,7 +43,7 @@ import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker; import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; import org.springframework.ide.vscode.commons.rewrite.java.JavaMarkerVisitor; import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils; -import org.springframework.ide.vscode.commons.rewrite.maven.MavenProjectParser; +import org.springframework.ide.vscode.commons.rewrite.java.ProjectParser; public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeCodeActionDescriptor { @@ -58,7 +58,7 @@ public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeC @Override public CompilationUnit visitCompilationUnit(CompilationUnit cu, ExecutionContext p) { JavaSourceSet sourceSet = cu.getMarkers().findFirst(JavaSourceSet.class).orElse(null); - if (sourceSet != null && MavenProjectParser.TEST.equals(sourceSet.getName())) { + if (sourceSet != null && ProjectParser.TEST.equals(sourceSet.getName())) { return cu; } return super.visitCompilationUnit(cu, p); diff --git a/vscode-extensions/vscode-spring-boot/package.json b/vscode-extensions/vscode-spring-boot/package.json index 77f69949d..a17949fb3 100644 --- a/vscode-extensions/vscode-spring-boot/package.json +++ b/vscode-extensions/vscode-spring-boot/package.json @@ -76,24 +76,24 @@ "menus": { "editor/context": [ { - "when": "resourceFilename == pom.xml", + "when": "resourceFilename == pom.xml || resourceFilename == build.gradle", "command": "vscode-spring-boot.rewrite.list.refactorings", "group": "SpringBoot" }, { - "when": "resourceFilename == pom.xml", + "when": "resourceFilename == pom.xml || resourceFilename == build.gradle", "command": "vscode-spring-boot.rewrite.list.boot-upgrades", "group": "SpringBoot" } ], "explorer/context": [ { - "when": "resourceFilename == pom.xml && config.boot-java.rewrite.refactorings.on == true", + "when": "(resourceFilename == pom.xml || resourceFilename == build.gradle) && config.boot-java.rewrite.refactorings.on == true", "command": "vscode-spring-boot.rewrite.list.refactorings", "group": "SpringBoot" }, { - "when": "resourceFilename == pom.xml && config.boot-java.rewrite.refactorings.on == true", + "when": "(resourceFilename == pom.xml || resourceFilename == build.gradle) && config.boot-java.rewrite.refactorings.on == true", "command": "vscode-spring-boot.rewrite.list.boot-upgrades", "group": "SpringBoot" }