diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 128c4ba..9055989 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -3,8 +3,6 @@ name: CI on: workflow_dispatch: push: - branches: - - main paths-ignore: - '.github/**' @@ -27,14 +25,28 @@ jobs: java: 17 name: CI Build ${{ matrix.nickname }} steps: - - name: Set git config for long paths - if: runner.os == 'Windows' - run: | - git config --system core.longpaths true - uses: actions/checkout@v4 + - uses: jvalkeal/setup-maven@v1 + with: + maven-version: 3.6.3 - uses: actions/setup-java@v4 with: distribution: liberica java-version: ${{ matrix.java }} - - name: Build + - name: Setup docker (missing on MacOS) + if: runner.os == 'macos' + run: | + brew install docker + colima start + + # For testcontainers to find the Colima socket + # https://github.com/abiosoft/colima/blob/main/docs/FAQ.md#cannot-connect-to-the-docker-daemon-at-unixvarrundockersock-is-the-docker-daemon-running + sudo ln -sf $HOME/.colima/default/docker.sock /var/run/docker.sock + - name: Verify formatting + run: mvn -B -Pfunctional-tests spring-javaformat:validate + - name: Build (Windows, no functional tests) + if: runner.os == 'Windows' run: ./mvnw -B clean verify + - name: Build (Non Windows) + if: runner.os != 'Windows' + run: ./mvnw -B -Pfunctional-tests clean verify \ No newline at end of file diff --git a/README.adoc b/README.adoc index 47e2c05..c1c698d 100644 --- a/README.adoc +++ b/README.adoc @@ -30,6 +30,7 @@ ____ compile 'org.springframework.rewrite:spring-rewrite-commons-launcher:{projectVersion}' ---- + === Implement a Recipe Launcher [source,java] diff --git a/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java b/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java index a8d9986..4767716 100644 --- a/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java +++ b/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java @@ -102,16 +102,17 @@ public class PrivateArtifactRepositoryTest { public static final String DEPENDENCY_CLASS_FQNAME = "com.example.dependency.DependencyClass"; private static final String NEW_USER_HOME = Path.of(".") - .resolve(TESTCODE_DIR + "/user.home") - .toAbsolutePath() - .normalize() - .toString(); + .resolve(TESTCODE_DIR + "/user.home") + .toAbsolutePath() + .normalize() + .toString(); + private static final File LOCAL_MAVEN_REPOSITORY = Path.of(NEW_USER_HOME + "/.m2/repository").toFile(); private static final Path DEPENDENCY_PATH_IN_LOCAL_MAVEN_REPO = Path - .of(NEW_USER_HOME + "/.m2/repository/com/example/dependency/dependency-project") - .toAbsolutePath() - .normalize(); + .of(NEW_USER_HOME + "/.m2/repository/com/example/dependency/dependency-project") + .toAbsolutePath() + .normalize(); // File path was too long under Windows when Maven repository was under TESTCODE_DIR + // "/reposilite-data" @@ -356,6 +357,7 @@ public class PrivateArtifactRepositoryTest { throw new RuntimeException("Could not create target dir"); } } + } } diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/MavenProject.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/MavenProject.java index 32ec7d6..80657b2 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/MavenProject.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/MavenProject.java @@ -25,6 +25,7 @@ import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; import org.springframework.rewrite.parsers.maven.MavenRuntimeInformation; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.rewrite.utils.ResourceUtil; import java.io.File; @@ -88,15 +89,26 @@ public class MavenProject { return pomFile; } + /** + * @return absolute Path of Module + */ + public Path getModulePath() { + return projectRoot.resolve(getModuleDir()); + } + + /** + * @return Path for Module relative to {@code baseDir}. + */ public Path getModuleDir() { if (getBasedir() == null) { return null; } - else if (projectRoot.relativize(ResourceUtil.getPath(pomFile)).toString().equals("pom.xml")) { + else if ("pom.xml" + .equals(LinuxWindowsPathUnifier.relativize(projectRoot, ResourceUtil.getPath(pomFile)).toString())) { return Path.of(""); } else { - return projectRoot.relativize(ResourceUtil.getPath(pomFile)).getParent(); + return LinuxWindowsPathUnifier.relativize(projectRoot, ResourceUtil.getPath(pomFile)).getParent(); } } @@ -218,7 +230,11 @@ public class MavenProject { @NotNull private static Predicate whenIn(Path sourceDirectory) { - return r -> ResourceUtil.getPath(r).toString().startsWith(sourceDirectory.toString()); + return r -> { + String resourcePath = LinuxWindowsPathUnifier.unifiedPathString(r); + String sourceDirectoryPath = LinuxWindowsPathUnifier.unifiedPathString(sourceDirectory); + return resourcePath.startsWith(sourceDirectoryPath); + }; } public List getJavaSourcesInTarget() { @@ -230,11 +246,12 @@ public class MavenProject { } public List getMainJavaSources() { - return listJavaSources(resources, getProjectRoot().resolve(getModuleDir()).resolve("src/main/java")); + Path sourceDir = getProjectRoot().resolve(getModuleDir()).resolve("src/main/java"); + return listJavaSources(resources, sourceDir); } - public Path getModulePath() { - return projectRoot.resolve(getModuleDir()); + public List getTestJavaSources() { + return listJavaSources(resources, getProjectRoot().resolve(getModuleDir()).resolve("src/test/java")); } public ProjectId getProjectId() { diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/ProjectScanner.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/ProjectScanner.java index e9d20bb..2ca74d2 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/ProjectScanner.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/ProjectScanner.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -57,9 +58,8 @@ public class ProjectScanner { if (!baseDir.toFile().exists()) { throw new IllegalArgumentException("Provided path does not exist: " + baseDir); } - Path absoluteRootPath = baseDir.toAbsolutePath(); - String unifiedPath = new LinuxWindowsPathUnifier().unifyPath(absoluteRootPath.toString() + "/**"); - String pattern = "file:" + unifiedPath; + Path absoluteRootPath = baseDir; + String pattern = "file:" + absoluteRootPath.toString() + "/**"; try { Resource[] resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader) .getResources(pattern); @@ -72,7 +72,7 @@ public class ProjectScanner { int numIgnored = resources.length - numResulting; LOGGER.debug("Scan returns %s resources, %d resources were ignored.".formatted(numResulting, numIgnored)); LOGGER.trace("Resources resulting from scan: %s".formatted(resultingResources.stream() - .map(r -> absoluteRootPath.relativize(ResourceUtil.getPath(r)).toString()) + .map(getResourceStringFunction(absoluteRootPath)) .collect(Collectors.joining(", ")))); return resultingResources; @@ -82,6 +82,11 @@ public class ProjectScanner { } } + @NotNull + private static Function getResourceStringFunction(Path absoluteRootPath) { + return r -> LinuxWindowsPathUnifier.relativize(absoluteRootPath, ResourceUtil.getPath(r)).toString(); + } + @NotNull private List filterIgnoredResources(Path baseDir, Resource[] resources) { Set effectivePathMatcherPatterns = new HashSet<>(); diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteProjectParser.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteProjectParser.java index 317b58b..8ec7bd7 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteProjectParser.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteProjectParser.java @@ -35,6 +35,8 @@ import org.springframework.rewrite.parsers.maven.MavenProjectAnalyzer; import org.springframework.rewrite.parsers.maven.ProvenanceMarkerFactory; import org.springframework.rewrite.recipes.RewriteRecipeDiscovery; import org.springframework.rewrite.scopes.ScanScope; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; +import org.springframework.util.StringUtils; import java.nio.file.Path; import java.util.ArrayList; @@ -120,7 +122,7 @@ public class RewriteProjectParser { } /** - * Parse given {@link Resource}s in {@code baseDir} to OpenRewrite AST representation. + * Parse given {@link Resource}s in {@code baseDir} to OpenRewrite LST. */ public RewriteProjectParsingResult parse(Path givenBaseDir, List resources) { scanScope.clear(beanFactory); @@ -175,8 +177,8 @@ public class RewriteProjectParser { if (!givenBaseDir.isAbsolute()) { givenBaseDir = givenBaseDir.toAbsolutePath().normalize(); } - final Path baseDir = givenBaseDir; - return baseDir; + String cleanedPath = StringUtils.cleanPath(givenBaseDir.toString()); + return Path.of(cleanedPath); } } diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteResourceParser.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteResourceParser.java index b832202..1d0a8e6 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteResourceParser.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/RewriteResourceParser.java @@ -90,7 +90,6 @@ public class RewriteResourceParser { } public Stream parse(Path searchDir, List resources, Set alreadyParsed) { - // TODO: 945 remove/clean this up List resourcesLeft = resources.stream() .filter(r -> alreadyParsed.stream() .noneMatch(path -> ResourceUtil.getPath(r).toString().startsWith(path.toString()))) diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/BuildFileParser.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/BuildFileParser.java index 8b84141..5eefa5c 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/BuildFileParser.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/BuildFileParser.java @@ -15,6 +15,7 @@ */ package org.springframework.rewrite.parsers.maven; +import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; import org.openrewrite.Parser; import org.openrewrite.SourceFile; @@ -24,6 +25,7 @@ import org.openrewrite.xml.tree.Xml; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.rewrite.utils.ResourceUtil; import org.springframework.util.Assert; @@ -101,10 +103,15 @@ public class BuildFileParser { private List findResourcesWithoutProvenanceMarker(Path baseDir, List buildFileResources, Map> provenanceMarkers) { return buildFileResources.stream() - .filter(r -> !provenanceMarkers.containsKey(baseDir.resolve(ResourceUtil.getPath(r)).normalize())) + .filter(r -> !provenanceMarkers.containsKey(ResourceUtil.getPath(r))) .toList(); } + @NotNull + private static Path getUnifiedPath(Path baseDir, Resource r) { + return LinuxWindowsPathUnifier.unifiedPath(baseDir.resolve(ResourceUtil.getPath(r))); + } + private static List retrieveNonPomFiles(List buildFileResources) { return buildFileResources.stream() .filter(r -> !"pom.xml".equals(ResourceUtil.getPath(r).getFileName().toString())) @@ -167,7 +174,7 @@ public class BuildFileParser { private static boolean filterTestResources(Resource r) { String path = ResourceUtil.getPath(r).toString(); - boolean underTest = path.contains("src/test"); + boolean underTest = path.contains(Path.of("src/test").toString()); if (underTest) { LOGGER.info("Ignore build file '%s' having 'src/test' in its path indicating it's a build file for tests." .formatted(path)); diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenModuleParser.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenModuleParser.java index 72bc7b1..2105daa 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenModuleParser.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenModuleParser.java @@ -36,6 +36,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.rewrite.parsers.*; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.rewrite.utils.ResourceUtil; import java.io.InputStream; @@ -58,333 +59,344 @@ import static org.openrewrite.Tree.randomId; */ public class MavenModuleParser { - private static final Logger LOGGER = LoggerFactory.getLogger(MavenProvenanceMarkerFactory.class); + private static final Logger LOGGER = LoggerFactory.getLogger(MavenModuleParser.class); - private final SpringRewriteProperties springRewriteProperties; + private final SpringRewriteProperties springRewriteProperties; - public MavenModuleParser(SpringRewriteProperties springRewriteProperties) { - this.springRewriteProperties = springRewriteProperties; - } + public MavenModuleParser(SpringRewriteProperties springRewriteProperties) { + this.springRewriteProperties = springRewriteProperties; + } - public List parseModuleSourceFiles(List resources, MavenProject currentProject, - Xml.Document moduleBuildFile, List provenanceMarkers, List styles, - ExecutionContext executionContext, Path baseDir) { + public List parseModuleSourceFiles(List resources, MavenProject currentProject, + Xml.Document moduleBuildFile, List provenanceMarkers, List styles, + ExecutionContext executionContext, Path baseDir) { - List sourceFiles = new ArrayList<>(); - // 146:149: get source encoding from maven - // TDOD: - // String s = - // moduleBuildFile.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getProperties().get("project.build.sourceEncoding"); - // if (mavenSourceEncoding != null) { - // ParsingExecutionContextView.view(ctx).setCharset(Charset.forName(mavenSourceEncoding.toString())); - // } - Object mavenSourceEncoding = currentProject.getProjectEncoding(); - if (mavenSourceEncoding != null) { - ParsingExecutionContextView.view(executionContext) - .setCharset(Charset.forName(mavenSourceEncoding.toString())); - } + List sourceFiles = new ArrayList<>(); + // 146:149: get source encoding from maven + // TDOD: + // String s = + // moduleBuildFile.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getProperties().get("project.build.sourceEncoding"); + // if (mavenSourceEncoding != null) { + // ParsingExecutionContextView.view(ctx).setCharset(Charset.forName(mavenSourceEncoding.toString())); + // } + Object mavenSourceEncoding = currentProject.getProjectEncoding(); + if (mavenSourceEncoding != null) { + ParsingExecutionContextView.view(executionContext) + .setCharset(Charset.forName(mavenSourceEncoding.toString())); + } - JavaParser.Builder javaParserBuilder = JavaParser.fromJavaVersion() - .styles(styles) - .logCompilationWarningsAndErrors(false); + JavaParser.Builder javaParserBuilder = JavaParser.fromJavaVersion() + .styles(styles) + .logCompilationWarningsAndErrors(false); - Path buildFilePath = currentProject.getBasedir().resolve(moduleBuildFile.getSourcePath()); - LOGGER.info("Parsing module " + buildFilePath); - // these paths will be ignored by ResourceParser - Set skipResourceScanDirs = pathsToOtherMavenProjects(currentProject, buildFilePath); - RewriteResourceParser rp = new RewriteResourceParser(baseDir, springRewriteProperties.getIgnoredPathPatterns(), - springRewriteProperties.getPlainTextMasks(), springRewriteProperties.getSizeThresholdMb(), - skipResourceScanDirs, javaParserBuilder.clone(), executionContext); + Path buildFilePath = currentProject.getBasedir().resolve(moduleBuildFile.getSourcePath()); + LOGGER.info("Parsing module " + buildFilePath); + // these paths will be ignored by ResourceParser + Set skipResourceScanDirs = pathsToOtherMavenProjects(currentProject, buildFilePath); + RewriteResourceParser rp = new RewriteResourceParser(baseDir, springRewriteProperties.getIgnoredPathPatterns(), + springRewriteProperties.getPlainTextMasks(), springRewriteProperties.getSizeThresholdMb(), + skipResourceScanDirs, javaParserBuilder.clone(), executionContext); - Set alreadyParsed = new HashSet<>(); - Path moduleBuildFilePath = baseDir.resolve(moduleBuildFile.getSourcePath()); - alreadyParsed.add(moduleBuildFilePath); - alreadyParsed.addAll(skipResourceScanDirs); - SourceSetParsingResult mainSourcesParsingResult = parseMainSources(baseDir, currentProject, moduleBuildFile, - resources, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext); - SourceSetParsingResult testSourcesParsingResult = parseTestSources(baseDir, currentProject, moduleBuildFile, - javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext, resources, - mainSourcesParsingResult.classpath()); - // Collect the dirs of modules parsed in previous steps + Set alreadyParsed = new HashSet<>(); + Path moduleBuildFilePath = baseDir.resolve(moduleBuildFile.getSourcePath()); + alreadyParsed.add(moduleBuildFilePath); + alreadyParsed.addAll(skipResourceScanDirs); - // parse other project resources - Stream parsedResourceFiles = rp.parse(moduleBuildFilePath.getParent(), resources, alreadyParsed) - // FIXME: handle generated sources - .map(addProvenance(baseDir, provenanceMarkers, null)); + SourceSetParsingResult mainSourcesParsingResult = processMainSources(baseDir, resources, moduleBuildFile, + javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, currentProject); - List mainAndTestSources = mergeAndFilterExcluded(baseDir, - springRewriteProperties.getIgnoredPathPatterns(), mainSourcesParsingResult.sourceFiles(), - testSourcesParsingResult.sourceFiles()); - List resourceFilesList = parsedResourceFiles.toList(); - sourceFiles.addAll(mainAndTestSources); - sourceFiles.addAll(resourceFilesList); + SourceSetParsingResult testSourcesParsingResult = processTestSources(baseDir, moduleBuildFile, + javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, currentProject, resources, + mainSourcesParsingResult.classpath()); + // Collect the dirs of modules parsed in previous steps - return sourceFiles; - } + // parse other project resources + Stream parsedResourceFiles = rp.parse(moduleBuildFilePath.getParent(), resources, alreadyParsed) + // FIXME: handle generated sources + .map(addProvenance(baseDir, provenanceMarkers, null)); + List mainAndTestSources = mergeAndFilterExcluded(baseDir, + springRewriteProperties.getIgnoredPathPatterns(), mainSourcesParsingResult.sourceFiles(), + testSourcesParsingResult.sourceFiles()); + List resourceFilesList = parsedResourceFiles.toList(); + sourceFiles.addAll(mainAndTestSources); + sourceFiles.addAll(resourceFilesList); - /** - * Add {@link Marker}s to {@link SourceFile}. - */ - public UnaryOperator addProvenance(Path baseDir, List provenance, - @Nullable Collection generatedSources) { - return s -> { - Markers markers = s.getMarkers(); - for (Marker marker : provenance) { - markers = markers.addIfAbsent(marker); - } - if (generatedSources != null && generatedSources.contains(baseDir.resolve(s.getSourcePath()))) { - markers = markers.addIfAbsent(new Generated(randomId())); - } - return s.withMarkers(markers); - }; - } + return sourceFiles; + } - private List mergeAndFilterExcluded(Path baseDir, Set exclusions, List mainSources, - List testSources) { - List pathMatchers = exclusions.stream() - .map(pattern -> baseDir.getFileSystem().getPathMatcher("glob:" + pattern)) - .toList(); - if (pathMatchers.isEmpty()) { - return Stream.concat(mainSources.stream(), testSources.stream()).toList(); - } - return new ArrayList<>(Stream.concat(mainSources.stream(), testSources.stream()) - .filter(s -> isNotExcluded(baseDir, pathMatchers, s)) - .toList()); - } + /** + * Add {@link Marker}s to {@link SourceFile}. + */ + public UnaryOperator addProvenance(Path baseDir, List provenance, + @Nullable Collection generatedSources) { + return s -> { + Markers markers = s.getMarkers(); + for (Marker marker : provenance) { + markers = markers.addIfAbsent(marker); + } + if (generatedSources != null && generatedSources.contains(baseDir.resolve(s.getSourcePath()))) { + markers = markers.addIfAbsent(new Generated(randomId())); + } + return s.withMarkers(markers); + }; + } - private static boolean isNotExcluded(Path baseDir, List exclusions, SourceFile s) { - return exclusions.stream() - .noneMatch(pm -> pm.matches(baseDir.resolve(s.getSourcePath()).toAbsolutePath().normalize())); - } + private List mergeAndFilterExcluded(Path baseDir, Set exclusions, List mainSources, + List testSources) { + List pathMatchers = exclusions.stream() + .map(pattern -> baseDir.getFileSystem().getPathMatcher("glob:" + pattern)) + .toList(); + if (pathMatchers.isEmpty()) { + return Stream.concat(mainSources.stream(), testSources.stream()).toList(); + } + return new ArrayList<>(Stream.concat(mainSources.stream(), testSources.stream()) + .filter(s -> isNotExcluded(baseDir, pathMatchers, s)) + .toList()); + } - private SourceSetParsingResult parseTestSources(Path baseDir, MavenProject mavenProject, - Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, - RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, - ExecutionContext executionContext, List resources, List classpath) { - return processTestSources(baseDir, moduleBuildFile, javaParserBuilder, rp, - provenanceMarkers, alreadyParsed, executionContext, mavenProject, resources, classpath); - } + private static boolean isNotExcluded(Path baseDir, List exclusions, SourceFile s) { + return exclusions.stream() + .noneMatch(pm -> pm.matches(baseDir.resolve(s.getSourcePath()).toAbsolutePath().normalize())); + } - /** - * - */ - private SourceSetParsingResult parseMainSources(Path baseDir, MavenProject mavenProject, - Xml.Document moduleBuildFile, List resources, - JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, - List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext) { + private Set pathsToOtherMavenProjects(MavenProject mavenProject, Path moduleBuildFile) { + return mavenProject.getCollectedProjects() + .stream() + .filter(p -> !p.getFile().toPath().toString().equals(moduleBuildFile.toString())) + .map(p -> p.getFile().toPath().getParent()) + .collect(Collectors.toSet()); + } - return processMainSources(baseDir, resources, moduleBuildFile, - javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject); - } + /** + * Parse Java sources and resources under {@code src/main} of current module. + */ + public SourceSetParsingResult processMainSources(Path baseDir, List resources, + Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, + RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, + ExecutionContext executionContext, MavenProject currentProject) { + LOGGER.info("Processing main sources in module '%s'".formatted(currentProject.getProjectId())); + // FIXME: 945 + // Some annotation processors output generated sources to the /target directory. + // These are added for parsing but + // should be filtered out of the final SourceFile list. - private Set pathsToOtherMavenProjects(MavenProject mavenProject, Path moduleBuildFile) { - return mavenProject.getCollectedProjects() - .stream() - .filter(p -> !p.getFile().toPath().toString().equals(moduleBuildFile.toString())) - .map(p -> p.getFile().toPath().getParent()) - .collect(Collectors.toSet()); - } + List mainJavaSources = new ArrayList<>(); + List javaSourcesInTarget = currentProject.getJavaSourcesInTarget(); // listJavaSources(resources, + // currentProject.getBasedir().resolve(currentProject.getBuildDirectory())); + List javaSourcesInMain = currentProject.getMainJavaSources(); // listJavaSources(resources, + // currentProject.getBasedir().resolve(currentProject.getSourceDirectory())); + mainJavaSources.addAll(javaSourcesInTarget); + mainJavaSources.addAll(javaSourcesInMain); + LOGGER.info("[%s] Parsing main source files".formatted(currentProject)); - /** - * Parse Java sources and resources under {@code src/main} of current module. - */ - public SourceSetParsingResult processMainSources(Path baseDir, List resources, - Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, - RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, - ExecutionContext executionContext, MavenProject currentProject) { - LOGGER.info("Processing main sources in module '%s'".formatted(currentProject.getProjectId())); - // FIXME: 945 - // Some annotation processors output generated sources to the /target directory. - // These are added for parsing but - // should be filtered out of the final SourceFile list. + // FIXME 945 classpath + // - Resolve dependencies to non-reactor projects from Maven repository + // - Resolve dependencies to reactor projects by providing the sources + // javaParserBuilder.classpath(byte[]) - List mainJavaSources = new ArrayList<>(); - List javaSourcesInTarget = currentProject.getJavaSourcesInTarget(); // listJavaSources(resources, - // currentProject.getBasedir().resolve(currentProject.getBuildDirectory())); - List javaSourcesInMain = currentProject.getMainJavaSources(); // listJavaSources(resources, - // currentProject.getBasedir().resolve(currentProject.getSourceDirectory())); - mainJavaSources.addAll(javaSourcesInTarget); - mainJavaSources.addAll(javaSourcesInMain); + // we're processing a module here. The classpath of the module consists of all + // declared dependencies and their transitive dependencies too. + // For dependencies to projects that belong to the current rector... + // They'd either need to be built with Maven before to guarantee that the jars are + // installed to local Maven repo. + // Or, the classpath must be created from the sources of the project. - LOGGER.info("[%s] Parsing source files".formatted(currentProject)); + List dependencies = currentProject.getCompileClasspathElements(); - // FIXME 945 classpath - // - Resolve dependencies to non-reactor projects from Maven repository - // - Resolve dependencies to reactor projects by providing the sources - // javaParserBuilder.classpath(byte[]) + javaParserBuilder.classpath(dependencies); - // we're processing a module here. The classpath of the module consists of all - // declared dependencies and their transitive dependencies too. - // For dependencies to projects that belong to the current rector... - // They'd either need to be built with Maven before to guarantee that the jars are - // installed to local Maven repo. - // Or, the classpath must be created from the sources of the project. + LOGGER.info("Dependencies on main classpath: %s".formatted(dependencies)); - List dependencies = currentProject.getCompileClasspathElements(); + JavaTypeCache typeCache = new JavaTypeCache(); + javaParserBuilder.typeCache(typeCache); - javaParserBuilder.classpath(dependencies); + Iterable inputs = mainJavaSources.stream().map(r -> { + FileAttributes fileAttributes = null; + Path path = ResourceUtil.getPath(r); + boolean isSynthetic = Files.exists(path); + Supplier inputStreamSupplier = () -> ResourceUtil.getInputStream(r); + Parser.Input input = new Parser.Input(path, fileAttributes, inputStreamSupplier, isSynthetic); + return input; + }).toList(); - JavaTypeCache typeCache = new JavaTypeCache(); - javaParserBuilder.typeCache(typeCache); + LOGGER.info("Parsing main Java sources."); - Iterable inputs = mainJavaSources.stream().map(r -> { - FileAttributes fileAttributes = null; - Path path = ResourceUtil.getPath(r); - boolean isSynthetic = Files.exists(path); - Supplier inputStreamSupplier = () -> ResourceUtil.getInputStream(r); - Parser.Input input = new Parser.Input(path, fileAttributes, inputStreamSupplier, isSynthetic); - return input; - }).toList(); + Set localClassesCp = new HashSet<>(); + JavaSourceSet javaSourceSet = sourceSet("main", dependencies, typeCache); + List cus = javaParserBuilder.build() + .parseInputs(inputs, baseDir, executionContext) + .peek(s -> { + ((J.CompilationUnit) s).getClasses() + .stream() + .map(J.ClassDeclaration::getType) + .forEach(localClassesCp::add); - Set localClassesCp = new HashSet<>(); - JavaSourceSet javaSourceSet = sourceSet("main", dependencies, typeCache); - List cus = javaParserBuilder.build() - .parseInputs(inputs, baseDir, executionContext) - .peek(s -> { - ((J.CompilationUnit) s).getClasses() - .stream() - .map(J.ClassDeclaration::getType) - .forEach(localClassesCp::add); + alreadyParsed.add(baseDir.resolve(s.getSourcePath())); + }) + .toList(); - alreadyParsed.add(baseDir.resolve(s.getSourcePath())); - }) - .toList(); + LOGGER.info("Parsed %d main Java source files.".formatted(cus.size())); - // TODO: This is a hack: - // Parsed java sources are not themselves on the classpath (here). - // The actual parsing happens when the stream is terminated (toList), - // therefore the toList() must be called before the parsed compilation units can - // be added to the classpath - List mainProjectProvenance = new ArrayList<>(provenanceMarkers); - javaSourceSet = appendToClasspath(localClassesCp, javaSourceSet); - mainProjectProvenance.add(javaSourceSet); + // TODO: This is a hack: + // Parsed java sources are not themselves on the classpath (here). + // The actual parsing happens when the stream is terminated (toList), + // therefore the toList() must be called before the parsed compilation units can + // be added to the classpath + List mainProjectProvenance = new ArrayList<>(provenanceMarkers); + javaSourceSet = appendToClasspath(localClassesCp, javaSourceSet); + mainProjectProvenance.add(javaSourceSet); - List parsedJavaPaths = javaSourcesInTarget.stream().map(ResourceUtil::getPath).toList(); - Stream parsedJava = cus.stream() - .map(addProvenance(baseDir, mainProjectProvenance, parsedJavaPaths)); - LOGGER.debug( - "[%s] Scanned %d java source files in main scope.".formatted(currentProject, mainJavaSources.size())); + List parsedJavaPaths = javaSourcesInTarget.stream().map(ResourceUtil::getPath).toList(); + Stream parsedMainJava = cus.stream() + .map(addProvenance(baseDir, mainProjectProvenance, parsedJavaPaths)); + LOGGER.debug( + "[%s] Scanned %d java source files in main scope.".formatted(currentProject, mainJavaSources.size())); - // Filter out any generated source files from the returned list, as we do not want - // to apply the recipe to the - // generated files. - Path buildDirectory = Paths.get(currentProject.getBuildDirectory()); - List sourceFiles = parsedJava.filter(s -> !s.getSourcePath().startsWith(buildDirectory)) - .collect(Collectors.toCollection(ArrayList::new)); + // Filter out any generated source files from the returned list, as we do not want + // to apply the recipe to the + // generated files. + Path buildDirectory = LinuxWindowsPathUnifier.unifiedPath(Paths.get(currentProject.getBuildDirectory())); + List filteredMainJava = filterOutResourcesInDir(parsedMainJava, buildDirectory); - int sourcesParsedBefore = alreadyParsed.size(); - alreadyParsed.addAll(parsedJavaPaths); - List parsedResourceFiles = rp - .parse(currentProject.getModulePath().resolve("src/main/resources"), resources, alreadyParsed) - .map(addProvenance(baseDir, mainProjectProvenance, null)) - .toList(); + int sourcesParsedBefore = alreadyParsed.size(); + alreadyParsed.addAll(parsedJavaPaths); - LOGGER.debug("[%s] Scanned %d resource files in main scope.".formatted(currentProject, - (alreadyParsed.size() - sourcesParsedBefore))); - // Any resources parsed from "main/resources" should also have the main source set - // added to them. - sourceFiles.addAll(parsedResourceFiles); - return new SourceSetParsingResult(sourceFiles, javaSourceSet.getClasspath()); - } + List resourcesLeft = resources.stream() + .filter(r -> alreadyParsed.stream().noneMatch(path -> LinuxWindowsPathUnifier.pathStartsWith(r, path))) + .toList(); - /** - * Add entries that don't exist in the classpath of {@code javaSourceSet} from - * {@code appendingClasspath}. - */ - @NotNull - private static JavaSourceSet appendToClasspath(Set appendingClasspath, - JavaSourceSet javaSourceSet) { - List curCp = javaSourceSet.getClasspath(); - appendingClasspath.forEach(f -> { - if (!curCp.contains(f)) { - curCp.add(f); - } - }); - javaSourceSet = javaSourceSet.withClasspath(new ArrayList<>(curCp)); - return javaSourceSet; - } + LOGGER.info("Parsing main resources"); + List parsedResourceFiles = rp + .parseSourceFiles(currentProject.getModulePath().resolve("src/main/resources"), resourcesLeft, + alreadyParsed, executionContext) + .map(addProvenance(baseDir, mainProjectProvenance, null)) + .toList(); - @NotNull - private static JavaSourceSet sourceSet(String name, List dependencies, JavaTypeCache typeCache) { - return JavaSourceSet.build(name, dependencies, typeCache, false); - } + LOGGER.info("Parsed %d main resources".formatted(parsedResourceFiles.size())); - /** - * Parse Java sources and resource files under {@code src/test}. - */ - public SourceSetParsingResult processTestSources(Path baseDir, Xml.Document moduleBuildFile, - JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, - List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, - MavenProject currentProject, List resources, List classpath) { - LOGGER.info("Processing test sources in module '%s'".formatted(currentProject.getProjectId())); + // TODO: Remove + // List parsedResourceFiles = rp + // .parse(currentProject.getModulePath().resolve("src/main/resources"), resources, + // alreadyParsed) + // .map(addProvenance(baseDir, mainProjectProvenance, null)) + // .toList(); - List testDependencies = currentProject.getTestClasspathElements(); + LOGGER.debug("[%s] Scanned %d resource files in main scope.".formatted(currentProject, + (alreadyParsed.size() - sourcesParsedBefore))); + // Any resources parsed from "main/resources" should also have the main source set + // added to them. + filteredMainJava.addAll(parsedResourceFiles); + return new SourceSetParsingResult(filteredMainJava, javaSourceSet.getClasspath()); + } - javaParserBuilder.classpath(testDependencies); - JavaTypeCache typeCache = new JavaTypeCache(); - javaParserBuilder.typeCache(typeCache); + @NotNull + private static ArrayList filterOutResourcesInDir(Stream parsedJava, Path buildDirectory) { + return parsedJava.filter(s -> !s.getSourcePath().startsWith(buildDirectory)) + .collect(Collectors.toCollection(ArrayList::new)); + } - List testJavaSources = listJavaSources(resources, - currentProject.getBasedir().resolve(currentProject.getTestSourceDirectory())); - alreadyParsed.addAll(testJavaSources.stream().map(ResourceUtil::getPath).toList()); + /** + * Add entries that don't exist in the classpath of {@code javaSourceSet} from + * {@code appendingClasspath}. + */ + @NotNull + private static JavaSourceSet appendToClasspath(Set appendingClasspath, + JavaSourceSet javaSourceSet) { + List curCp = javaSourceSet.getClasspath(); + appendingClasspath.forEach(f -> { + if (!curCp.contains(f)) { + curCp.add(f); + } + }); + javaSourceSet = javaSourceSet.withClasspath(new ArrayList<>(curCp)); + return javaSourceSet; + } - Iterable inputs = testJavaSources.stream() - .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) - .toList(); + @NotNull + private static JavaSourceSet sourceSet(String name, List dependencies, JavaTypeCache typeCache) { + return JavaSourceSet.build(name, dependencies, typeCache, false); + } - final List localClassesCp = new ArrayList<>(); - List cus = javaParserBuilder.build() - .parseInputs(inputs, baseDir, executionContext) - .peek(s -> { - ((J.CompilationUnit) s).getClasses() - .stream() - .map(J.ClassDeclaration::getType) - .forEach(localClassesCp::add); - alreadyParsed.add(baseDir.resolve(s.getSourcePath())); - }) - .toList(); + /** + * Parse Java sources and resource files under {@code src/test}. + */ + public SourceSetParsingResult processTestSources(Path baseDir, Xml.Document moduleBuildFile, + JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, + List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, + MavenProject currentProject, List resources, List classpath) { + LOGGER.info("Processing test sources in module '%s'".formatted(currentProject.getProjectId())); - List markers = new ArrayList<>(provenanceMarkers); + List testDependencies = currentProject.getTestClasspathElements(); - JavaSourceSet javaSourceSet = sourceSet("test", testDependencies, typeCache); - Set curClasspath = Stream.concat(classpath.stream(), localClassesCp.stream()) - .collect(Collectors.toSet()); - javaSourceSet = appendToClasspath(curClasspath, javaSourceSet); - markers.add(javaSourceSet); - Stream parsedJava = cus.stream().map(addProvenance(baseDir, markers, null)); + javaParserBuilder.classpath(testDependencies); + JavaTypeCache typeCache = new JavaTypeCache(); + javaParserBuilder.typeCache(typeCache); - LOGGER.debug( - "[%s] Scanned %d java source files in test scope.".formatted(currentProject, testJavaSources.size())); - Stream sourceFiles = parsedJava; + List testJavaSources = currentProject.getTestJavaSources(); + // listJavaSources(resources, + // currentProject.getBasedir().resolve(currentProject.getTestSourceDirectory())); + // alreadyParsed.addAll(testJavaSources.stream().map(ResourceUtil::getPath).toList()); - // Any resources parsed from "test/resources" should also have the test source set - // added to them. - int sourcesParsedBefore = alreadyParsed.size(); - Stream parsedResourceFiles = rp - .parse(currentProject.getBasedir().resolve("src/test/resources"), resources, alreadyParsed) - .map(addProvenance(baseDir, markers, null)); - LOGGER.debug("[%s] Scanned %d resource files in test scope.".formatted(currentProject, - (alreadyParsed.size() - sourcesParsedBefore))); - sourceFiles = Stream.concat(sourceFiles, parsedResourceFiles); - List result = sourceFiles.toList(); - return new SourceSetParsingResult(result, javaSourceSet.getClasspath()); - } + Iterable inputs = testJavaSources.stream() + .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) + .toList(); - // FIXME: 945 take Java sources from resources - private static List listJavaSources(List resources, Path sourceDirectory) { - return resources.stream().filter(whenIn(sourceDirectory)).filter(whenFileNameEndsWithJava()).toList(); - } + final List localClassesCp = new ArrayList<>(); + List cus = javaParserBuilder.build() + .parseInputs(inputs, baseDir, executionContext) + .peek(s -> { + ((J.CompilationUnit) s).getClasses() + .stream() + .map(J.ClassDeclaration::getType) + .forEach(localClassesCp::add); + alreadyParsed.add(baseDir.resolve(s.getSourcePath())); + }) + .toList(); - @NotNull - private static Predicate whenFileNameEndsWithJava() { - return p -> ResourceUtil.getPath(p).getFileName().toString().endsWith(".java"); - } + List markers = new ArrayList<>(provenanceMarkers); - @NotNull - private static Predicate whenIn(Path sourceDirectory) { - return r -> ResourceUtil.getPath(r).toString().startsWith(sourceDirectory.toString()); - } + JavaSourceSet javaSourceSet = sourceSet("test", testDependencies, typeCache); + Set curClasspath = Stream.concat(classpath.stream(), localClassesCp.stream()) + .collect(Collectors.toSet()); + javaSourceSet = appendToClasspath(curClasspath, javaSourceSet); + markers.add(javaSourceSet); + Stream parsedJava = cus.stream().map(addProvenance(baseDir, markers, null)); + + LOGGER.debug( + "[%s] Scanned %d java source files in test scope.".formatted(currentProject, testJavaSources.size())); + Stream sourceFiles = parsedJava; + + // Any resources parsed from "test/resources" should also have the test source set + // added to them. + int sourcesParsedBefore = alreadyParsed.size(); + Stream parsedResourceFiles = rp + .parse(currentProject.getBasedir().resolve("src/test/resources"), resources, alreadyParsed) + .map(addProvenance(baseDir, markers, null)); + LOGGER.debug("[%s] Scanned %d resource files in test scope.".formatted(currentProject, + (alreadyParsed.size() - sourcesParsedBefore))); + sourceFiles = Stream.concat(sourceFiles, parsedResourceFiles); + List result = sourceFiles.toList(); + return new SourceSetParsingResult(result, javaSourceSet.getClasspath()); + } + + // FIXME: 945 take Java sources from resources + private static List listJavaSources(List resources, Path sourceDirectory) { + return resources.stream() + .filter(whenIn(LinuxWindowsPathUnifier.unifiedPath(sourceDirectory))) + .filter(whenFileNameEndsWithJava()) + .toList(); + } + + @NotNull + private static Predicate whenFileNameEndsWithJava() { + return p -> ResourceUtil.getPath(p).getFileName().toString().endsWith(".java"); + } + + @NotNull + private static Predicate whenIn(Path sourceDirectory) { + return r -> ResourceUtil.getPath(r).toString().startsWith(sourceDirectory.toString()); + } } diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzer.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzer.java index 0921d63..e30066b 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzer.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzer.java @@ -18,16 +18,19 @@ package org.springframework.rewrite.parsers.maven; import org.apache.maven.model.*; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.jetbrains.annotations.NotNull; import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.springframework.core.io.Resource; import org.springframework.rewrite.parsers.MavenProject; import org.springframework.rewrite.parsers.ParserContext; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.rewrite.utils.ResourceUtil; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.*; +import java.util.function.Predicate; import java.util.stream.Collectors; /** @@ -60,7 +63,7 @@ public class MavenProjectAnalyzer { } Resource rootPom = allPomFiles.stream() - .filter(r -> ResourceUtil.getPath(r).toString().equals(baseDir.resolve(POM_XML).normalize().toString())) + .filter(r -> LinuxWindowsPathUnifier.pathEquals(r, baseDir.resolve(POM_XML))) .findFirst() .orElseThrow( () -> new IllegalArgumentException("The provided resources do not contain a root 'pom.xml' file.")); @@ -78,12 +81,14 @@ public class MavenProjectAnalyzer { private List map(Path baseDir, List resources, List sortedModels) { List mavenProjects = new ArrayList<>(); sortedModels.stream().filter(Objects::nonNull).forEach(m -> { - String projectDir = baseDir.resolve(m.getProjectDirectory().toString()).normalize().toString(); + String projectDir = LinuxWindowsPathUnifier + .unifiedPathString(baseDir.resolve(m.getProjectDirectory().toPath()).normalize()); List filteredResources = resources.stream() - .filter(r -> ResourceUtil.getPath(r).toString().startsWith(projectDir)) + .filter(r -> LinuxWindowsPathUnifier.unifiedPathString(r).startsWith(projectDir)) .toList(); - mavenProjects - .add(new MavenProject(baseDir, m.getResource(), m, rewriteMavenArtifactDownloader, filteredResources)); + MavenProject mavenProject = new MavenProject(baseDir, m.getResource(), m, rewriteMavenArtifactDownloader, + filteredResources); + mavenProjects.add(mavenProject); }); // set all non parent poms as collected projects for root parent pom List collected = new ArrayList<>(mavenProjects); @@ -108,15 +113,8 @@ public class MavenProjectAnalyzer { String modulePathSegment = path == null ? moduleName : path + "/" + moduleName; - allPomFiles.stream().filter(resource -> { - String modulePath = baseDir.resolve(modulePathSegment) - .resolve(POM_XML) - .toAbsolutePath() - .normalize() - .toString(); - String resourcePath = ResourceUtil.getPath(resource).toAbsolutePath().normalize().toString(); - return resourcePath.equals(modulePath); - }) + allPomFiles.stream() + .filter(getResourcePredicate(baseDir, modulePathSegment)) .map(Model::new) .forEach(m -> recursivelyFindReactorModules(baseDir, modulePathSegment, reactorModels, allPomFiles, m) .stream()); @@ -124,6 +122,16 @@ public class MavenProjectAnalyzer { return reactorModels; } + @NotNull + private static Predicate getResourcePredicate(Path baseDir, String modulePathSegment) { + return resource -> { + Path pomPath = baseDir.resolve(modulePathSegment).resolve(POM_XML).toAbsolutePath().normalize(); + String modulePath = LinuxWindowsPathUnifier.unifiedPathString(pomPath); + Path resourcePath = ResourceUtil.getPath(resource).toAbsolutePath().normalize(); + return LinuxWindowsPathUnifier.pathEquals(resourcePath, modulePath); + }; + } + public List sortModels(List reactorModels) { List sortedModels = new ArrayList<>(); Map gaToModelMap = reactorModels.stream().collect(Collectors.toMap(m -> { diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializer.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializer.java index f291947..640bc4e 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializer.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializer.java @@ -22,6 +22,7 @@ import org.openrewrite.maven.MavenSettings; import org.openrewrite.maven.internal.RawRepositories; import org.openrewrite.maven.tree.MavenRepository; import org.springframework.rewrite.scopes.ProjectMetadata; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.stereotype.Component; import java.nio.file.Files; @@ -50,9 +51,10 @@ public class MavenSettingsInitializer { } public void initializeMavenSettings() { - Path userHome = Path.of(System.getProperty("user.home")); + Path userHome = Path.of(System.getProperty("user.home")).toAbsolutePath().normalize(); String m2RepoPath = userHome.resolve(".m2/repository").toAbsolutePath().normalize() + "/"; - String repo = "file://" + m2RepoPath; + String unifiedM2RepoPath = LinuxWindowsPathUnifier.unifiedPathString(m2RepoPath); + String repo = "file://" + unifiedM2RepoPath; Path mavenSettingsFile = userHome.resolve(".m2/settings.xml"); Path mavenSecuritySettingsFile = userHome.resolve(".m2/settings-security.xml"); @@ -62,7 +64,7 @@ public class MavenSettingsInitializer { MavenSettings.@Nullable ActiveProfiles activeProfiles = new MavenSettings.ActiveProfiles(List.of("default")); MavenSettings.@Nullable Mirrors mirrors = new MavenSettings.Mirrors(); MavenSettings.Servers servers = new MavenSettings.Servers(); - MavenSettings mavenSettings = new MavenSettings(m2RepoPath, mavenRepository, profiles, activeProfiles, mirrors, + MavenSettings mavenSettings = new MavenSettings(repo, mavenRepository, profiles, activeProfiles, mirrors, servers); // TODO: Add support for global Maven settings (${maven.home}/conf/settings.xml). diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/ProvenanceMarkerFactory.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/ProvenanceMarkerFactory.java index 40fe12b..f63552b 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/ProvenanceMarkerFactory.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/parsers/maven/ProvenanceMarkerFactory.java @@ -18,6 +18,7 @@ package org.springframework.rewrite.parsers.maven; import org.openrewrite.marker.Marker; import org.springframework.core.io.Resource; import org.springframework.rewrite.parsers.ParserContext; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.rewrite.utils.ResourceUtil; import java.nio.file.Path; diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/LinuxWindowsPathUnifier.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/LinuxWindowsPathUnifier.java index 81e3c41..2140723 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/LinuxWindowsPathUnifier.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/LinuxWindowsPathUnifier.java @@ -15,6 +15,7 @@ */ package org.springframework.rewrite.utils; +import org.springframework.core.io.Resource; import org.springframework.util.StringUtils; import java.nio.file.Path; @@ -26,11 +27,26 @@ import java.nio.file.Path; */ public class LinuxWindowsPathUnifier { - public String unifyPath(Path path) { - return unifyPath(path.toString()); + public static Path relativize(Path subpath, Path path) { + LinuxWindowsPathUnifier linuxWindowsPathUnifier = new LinuxWindowsPathUnifier(); + String unifiedAbsoluteRootPath = linuxWindowsPathUnifier.unifiedPathString(subpath); + String pathUnified = linuxWindowsPathUnifier.unifiedPathString(path); + return Path.of(unifiedAbsoluteRootPath).relativize(Path.of(pathUnified)); } - public String unifyPath(String path) { + public static String unifiedPathString(Path path) { + return unifiedPathString(path.toString()); + } + + public static Path unifiedPath(Path path) { + return Path.of(unifiedPathString(path)); + } + + public static String unifiedPathString(Resource r) { + return unifiedPathString(ResourceUtil.getPath(r)); + } + + public static String unifiedPathString(String path) { path = StringUtils.cleanPath(path); if (isWindows()) { path = transformToLinuxPath(path); @@ -38,12 +54,32 @@ public class LinuxWindowsPathUnifier { return path; } - boolean isWindows() { + public static Path unifiedPath(String path) { + return Path.of(unifiedPathString(path)); + } + + static boolean isWindows() { return System.getProperty("os.name").contains("Windows"); } - private String transformToLinuxPath(String path) { + private static String transformToLinuxPath(String path) { return path.replaceAll("^[\\w]+:\\/?", "/"); } + public static boolean pathEquals(Resource r, Path path) { + return unifiedPathString(ResourceUtil.getPath(r)).equals(unifiedPathString(path.normalize())); + } + + public static boolean pathEquals(Path basedir, String parentPomPath) { + return unifiedPathString(basedir).equals(parentPomPath); + } + + public static boolean pathEquals(Path path1, Path path2) { + return unifiedPathString(path1).equals(unifiedPathString(path2)); + } + + public static boolean pathStartsWith(Resource r, Path path) { + return ResourceUtil.getPath(r).toString().startsWith(unifiedPathString(path)); + } + } diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/OsAgnosticPathMatcher.java b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/OsAgnosticPathMatcher.java index 4b8e674..30bf590 100644 --- a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/OsAgnosticPathMatcher.java +++ b/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/OsAgnosticPathMatcher.java @@ -48,7 +48,7 @@ public class OsAgnosticPathMatcher implements PathMatcher { } private String unifyPath(String path) { - return pathUnifier.unifyPath(path); + return pathUnifier.unifiedPathString(path); } @Override diff --git a/spring-rewrite-commons-launcher/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java b/spring-rewrite-commons-launcher/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java index 1e0c055..4ac0f2a 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java @@ -31,6 +31,7 @@ import org.springframework.rewrite.parsers.RewriteProjectParser; import org.springframework.rewrite.parsers.RewriteProjectParsingResult; import org.springframework.rewrite.test.util.DummyResource; import org.springframework.rewrite.test.util.TestProjectHelper; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import java.nio.file.Path; import java.util.List; @@ -100,7 +101,7 @@ public class CalculateClasspathTest { } """; - Path baseDir = tmpDir.resolve("/example-1").toAbsolutePath().normalize(); + Path baseDir = LinuxWindowsPathUnifier.unifiedPath(tmpDir.resolve("/example-1").toAbsolutePath().normalize()); List resources = List.of(new DummyResource(baseDir.resolve("pom.xml"), pom), new DummyResource(baseDir.resolve("src/main/java/com/example/MainClass.java"), mainClass), new DummyResource(baseDir.resolve("src/test/java/com/example/TestClass.java"), testClass)); @@ -109,13 +110,16 @@ public class CalculateClasspathTest { // verify types in use SourceFile mainSourceFile = parsingResult.sourceFiles().get(1); + assertThat(mainSourceFile).isInstanceOf(J.CompilationUnit.class); J.CompilationUnit mainCu = (J.CompilationUnit) mainSourceFile; + // Having Min annotation resolved proves type resolution is working for main // resources assertThat(mainCu.getTypesInUse().getTypesInUse().stream().map(t -> t.toString())) .containsExactlyInAnyOrder("int", "String", "javax.validation.constraints.Min"); SourceFile testSourceFile = parsingResult.sourceFiles().get(2); + assertThat(testSourceFile).isInstanceOf(J.CompilationUnit.class); J.CompilationUnit testCu = (J.CompilationUnit) testSourceFile; // Having Test annotation resolved proves type resolution is working for test // resources diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/BuildFileParserTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/BuildFileParserTest.java index 4200a6b..cc84bcd 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/BuildFileParserTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/BuildFileParserTest.java @@ -154,10 +154,20 @@ class BuildFileParserTest { Path module1SubmodulePomPath = baseDir.resolve(module1SubmoduleSourcePath); Path parentPomPath = baseDir.resolve(parentSourcePath); Path module1PomXml = baseDir.resolve(module1SourcePath); - Map> provenanceMarkers = Map.of(parentPomPath, - List.of(new JavaProject(UUID.randomUUID(), "parent", null)), module1PomXml, - List.of(new JavaProject(UUID.randomUUID(), "module1", null)), module1SubmodulePomPath, - List.of(new JavaProject(UUID.randomUUID(), "module1/submodule", null))); + + // @formatter:off + Map> provenanceMarkers = Map.of( + parentPomPath, List.of( + new JavaProject(UUID.randomUUID(), "parent", null) + ), + module1PomXml, List.of( + new JavaProject(UUID.randomUUID(), "module1", null) + ), + module1SubmodulePomPath, List.of( + new JavaProject(UUID.randomUUID(), "module1/submodule", null) + ) + ); + // @formatter:on ExecutionContext executionContext = new InMemoryExecutionContext(t -> t.printStackTrace()); boolean skipMavenParsing = false; @@ -196,14 +206,14 @@ class BuildFileParserTest { @DisplayName("parse with non-pom resources provided should throw exception") void parseWithNonPomResourcesProvidedShouldThrowException() { Path baseDir = Path.of(".").toAbsolutePath().normalize(); - Resource nonPomResource = new DummyResource(baseDir, "src/main/java/SomeClass.java", - "public class SomeClass {}"); + Path someClassPath = baseDir.resolve("src/main/java/SomeClass.java"); + Resource nonPomResource = new DummyResource(baseDir, someClassPath.toString(), "public class SomeClass {}"); List nonPomResource1 = List.of(nonPomResource); String message = assertThrows(IllegalArgumentException.class, () -> sut.parseBuildFiles(baseDir, nonPomResource1, List.of(), new InMemoryExecutionContext(), false, Map.of())) .getMessage(); - assertThat(message).isEqualTo("Provided resources which are not Maven build files: '[" + baseDir - + "/src/main/java/SomeClass.java]'"); + assertThat(message) + .isEqualTo("Provided resources which are not Maven build files: '[" + someClassPath + "]'"); } @Test @@ -213,20 +223,25 @@ class BuildFileParserTest { Path pom1Path = baseDir.resolve("pom.xml"); Resource pom1 = new DummyResource(pom1Path, ""); + Path pom2Path = baseDir.resolve("module1/pom.xml"); Resource pom2 = new DummyResource(pom2Path, ""); + List poms = List.of(pom1, pom2); - Map> provenanceMarkers = Map.of(pom1Path, - List.of(new JavaProject(UUID.randomUUID(), "pom.xml", null)) - // no marker for module1/pom.xml + // @formatter:off + Map> provenanceMarkers = Map.of( + pom1Path, List.of(new JavaProject(UUID.randomUUID(), "pom.xml", null)) + // no marker for module1/pom.xml ); - - String message = assertThrows(IllegalArgumentException.class, () -> sut.parseBuildFiles(baseDir, poms, - List.of(), new InMemoryExecutionContext(), false, provenanceMarkers)) + String message = assertThrows( + IllegalArgumentException.class, + () -> sut.parseBuildFiles(baseDir, poms, List.of(), new InMemoryExecutionContext(), false, provenanceMarkers) + ) .getMessage(); - assertThat(message).isEqualTo("No provenance marker provided for these pom files [" - + Path.of(".").toAbsolutePath().normalize().resolve("module1/pom.xml]")); + // @formatter:on + + assertThat(message).isEqualTo("No provenance marker provided for these pom files [" + pom2Path + "]"); } } diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/ParserEventPublicationIntegrationTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/ParserEventPublicationIntegrationTest.java index a17f8f5..7038328 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/ParserEventPublicationIntegrationTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/ParserEventPublicationIntegrationTest.java @@ -26,6 +26,7 @@ import org.springframework.core.io.Resource; import org.springframework.rewrite.parsers.events.FinishedParsingResourceEvent; import org.springframework.rewrite.parsers.events.StartedParsingProjectEvent; import org.springframework.rewrite.parsers.events.SuccessfullyParsedProjectEvent; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import java.nio.file.Path; import java.util.ArrayList; @@ -53,7 +54,7 @@ public class ParserEventPublicationIntegrationTest { @Autowired ExecutionContext executionContext; - private static List capturedEvents = new ArrayList<>(); + private static List capturedEvents = new ArrayList<>(); private static StartedParsingProjectEvent startedParsingEvent; @@ -69,19 +70,19 @@ public class ParserEventPublicationIntegrationTest { RewriteProjectParsingResult parsingResult = sut.parse(baseDir, resources); assertThat(parsingResult.sourceFiles()).hasSize(5); - assertThat(parsingResult.sourceFiles().stream().map(s -> s.getSourcePath().toString()).toList()) - .containsExactly("pom.xml", "module-b/pom.xml", "module-a/pom.xml", + assertThat(parsingResult.sourceFiles() + .stream() + .map(s -> LinuxWindowsPathUnifier.unifiedPathString(s.getSourcePath())) + .toList()).containsExactly("pom.xml", "module-b/pom.xml", "module-a/pom.xml", "module-b/src/test/resources/application.yaml", "module-a/src/main/java/com/acme/SomeClass.java"); assertThat(capturedEvents).hasSize(5); - assertThat(capturedEvents.get(0).sourceFile().getSourcePath().toString()).isEqualTo("pom.xml"); - assertThat(capturedEvents.get(1).sourceFile().getSourcePath().toString()).isEqualTo("module-b/pom.xml"); - assertThat(capturedEvents.get(2).sourceFile().getSourcePath().toString()).isEqualTo("module-a/pom.xml"); - assertThat(capturedEvents.get(3).sourceFile().getSourcePath().toString()) - .isEqualTo("module-b/src/test/resources/application.yaml"); - assertThat(capturedEvents.get(4).sourceFile().getSourcePath().toString()) - .isEqualTo("module-a/src/main/java/com/acme/SomeClass.java"); + assertThat(capturedEvents.get(0)).isEqualTo("pom.xml"); + assertThat(capturedEvents.get(1)).isEqualTo("module-b/pom.xml"); + assertThat(capturedEvents.get(2)).isEqualTo("module-a/pom.xml"); + assertThat(capturedEvents.get(3)).isEqualTo("module-b/src/test/resources/application.yaml"); + assertThat(capturedEvents.get(4)).isEqualTo("module-a/src/main/java/com/acme/SomeClass.java"); // ResourceParser not firing events // TODO: reactivate after // https://github.com/openrewrite/rewrite-maven-plugin/issues/622 @@ -99,7 +100,8 @@ public class ParserEventPublicationIntegrationTest { @EventListener(FinishedParsingResourceEvent.class) public void onEvent(FinishedParsingResourceEvent event) { - capturedEvents.add(event); + String unifiedPathString = LinuxWindowsPathUnifier.unifiedPathString(event.sourceFile().getSourcePath()); + capturedEvents.add(unifiedPathString); } @EventListener(StartedParsingProjectEvent.class) diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserIntegrationTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserIntegrationTest.java index 27bd40c..515ce36 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserIntegrationTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserIntegrationTest.java @@ -17,6 +17,9 @@ package org.springframework.rewrite.parsers; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junitpioneer.jupiter.Issue; import org.openrewrite.java.tree.J; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -33,6 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Fabian Krüger */ +@DisabledOnOs(value = OS.WINDOWS, disabledReason = "The repository URIs of dependencies differ.") +@Issue("https://github.com/spring-projects/spring-rewrite-commons/issues/12") @SpringBootTest(classes = { SbmSupportRewriteConfiguration.class, SbmTestConfiguration.class }) public class RewriteProjectParserIntegrationTest { diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserParityTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserParityTest.java index 4ff916e..e774fdc 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserParityTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/RewriteProjectParserParityTest.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; import org.junitpioneer.jupiter.Issue; import org.openrewrite.ExecutionContext; @@ -55,6 +57,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.fail; * * @author Fabian Krüger */ +@DisabledOnOs(value = OS.WINDOWS, disabledReason = "The repository URIs of dependencies differ.") +@Issue("https://github.com/spring-projects/spring-rewrite-commons/issues/12") class RewriteProjectParserParityTest { @Test @@ -163,14 +167,14 @@ class RewriteProjectParserParityTest { .verifyParity((comparingParsingResult, testedParsingResult) -> { assertThat( comparingParsingResult.sourceFiles().stream().map(sf -> sf.getSourcePath().toString()).toList()) - .contains("checkstyle/rules.xml"); + .contains(Path.of("checkstyle/rules.xml").toString()); assertThat( comparingParsingResult.sourceFiles().stream().map(sf -> sf.getSourcePath().toString()).toList()) - .contains("checkstyle/suppressions.xml"); + .contains(Path.of("checkstyle/suppressions.xml").toString()); assertThat(testedParsingResult.sourceFiles().stream().map(sf -> sf.getSourcePath().toString()).toList()) - .contains("checkstyle/rules.xml"); + .contains(Path.of("checkstyle/rules.xml").toString()); assertThat(testedParsingResult.sourceFiles().stream().map(sf -> sf.getSourcePath().toString()).toList()) - .contains("checkstyle/suppressions.xml"); + .contains(Path.of("checkstyle/suppressions.xml").toString()); }); } diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/SpringRewritePropertiesTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/SpringRewritePropertiesTest.java index 438a9e9..f898b65 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/SpringRewritePropertiesTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/SpringRewritePropertiesTest.java @@ -21,6 +21,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import java.io.File; +import java.nio.file.Path; + import static org.assertj.core.api.Assertions.assertThat; class SpringRewritePropertiesTest { @@ -42,7 +45,7 @@ class SpringRewritePropertiesTest { @DisplayName("spring.rewrite.pomCacheDirectory") void defaultPomCacheDirectory() { assertThat(springRewriteProperties.getPomCacheDirectory()) - .isEqualTo(System.getProperty("user.home") + "/.rewrite-cache"); + .isEqualTo(Path.of(System.getProperty("user.home")).resolve(".rewrite-cache").toString()); } @Test diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenMojoProjectParserFactory.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenMojoProjectParserFactory.java index 12be3ac..16d1ccf 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenMojoProjectParserFactory.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenMojoProjectParserFactory.java @@ -60,7 +60,7 @@ public class MavenMojoProjectParserFactory { Collection plainTextMasks, int sizeThresholdMb, boolean runPerSubmodule, PlexusContainer plexusContainer, MavenSession session) { try { - Log logger = new Slf4jToMavenLoggerAdapter(LOGGER); + Log logger = new Slf4jToMavenLoggerAdapter(LoggerFactory.getLogger(MavenMojoProjectParser.class)); RuntimeInformation runtimeInformation = plexusContainer.lookup(RuntimeInformation.class); SettingsDecrypter decrypter = plexusContainer.lookup(SettingsDecrypter.class); diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzerTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzerTest.java index a228bc3..c1e5182 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzerTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenProjectAnalyzerTest.java @@ -28,6 +28,7 @@ import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.springframework.core.io.Resource; import org.springframework.rewrite.parsers.MavenProject; import org.springframework.rewrite.test.util.DummyResource; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import org.springframework.rewrite.utils.ResourceUtil; import java.io.IOException; @@ -240,7 +241,7 @@ class MavenProjectAnalyzerTest { */ @Test @DisplayName("reactorBuild") - void reactorBuild() { + void getSortedProjectsWithMultiModule() { @Language("xml") String parentPom = """ @@ -272,18 +273,45 @@ class MavenProjectAnalyzerTest { """; - List resources = List.of(new DummyResource(Path.of("pom.xml"), parentPom), - new DummyResource(Path.of("example/pom.xml"), modulePom)); + String javaSource = """ + package com.example; + public class MainSource { - List sortedProjects = sut.getSortedProjects(Path.of(".").toAbsolutePath(), resources); + } + """; + + Path baseDir = Path.of(".").toAbsolutePath().normalize(); + Path exampleModuleDir = baseDir.resolve("example"); + + // @formatter:off + List resources = List.of( + new DummyResource(baseDir.resolve("pom.xml"), parentPom), + new DummyResource(exampleModuleDir.resolve("pom.xml"), modulePom), + new DummyResource(exampleModuleDir.resolve("src/main/java/com/acme/MainSource.java"), javaSource), + new DummyResource(exampleModuleDir.resolve("src/test/java/com/acme/MainSourceTest.java"), javaSource) + ); + // @formatter:on + + List sortedProjects = sut.getSortedProjects(baseDir, resources); assertThat(sortedProjects).hasSize(2); - String parentPomPath = Path.of(".").toAbsolutePath().normalize().toString(); - assertThat(sortedProjects.get(0).getBasedir().toString()).isEqualTo(parentPomPath); + MavenProject parentProject = sortedProjects.get(0); + MavenProject exampleProject = sortedProjects.get(1); + + assertThat(LinuxWindowsPathUnifier.pathEquals(baseDir.normalize(), parentProject.getBasedir())).isTrue(); + assertThat(LinuxWindowsPathUnifier.pathEquals(exampleProject.getBasedir(), + Path.of(".").resolve("example").toAbsolutePath().normalize())); + + assertThat(exampleProject.getMainJavaSources()).hasSize(1); + assertThat(LinuxWindowsPathUnifier + .unifiedPathString(ResourceUtil.getPath(exampleProject.getMainJavaSources().get(0))) + .endsWith("src/main/java/com/acme/MainSource.java")); + assertThat(exampleProject.getTestJavaSources()).hasSize(1); + assertThat(LinuxWindowsPathUnifier + .unifiedPathString(ResourceUtil.getPath(exampleProject.getMainJavaSources().get(0))) + .endsWith("src/test/java/com/acme/MainSourceTest.java")); - String modulePomPath = Path.of(".").resolve("example").toAbsolutePath().normalize().toString(); - assertThat(sortedProjects.get(1).getBasedir().toString()).isEqualTo(modulePomPath); } /** @@ -345,10 +373,10 @@ class MavenProjectAnalyzerTest { assertThat(sortedProjects).hasSize(2); String parentPomPath = Path.of(".").toAbsolutePath().normalize().toString(); - assertThat(sortedProjects.get(0).getBasedir().toString()).isEqualTo(parentPomPath); + assertThat(LinuxWindowsPathUnifier.pathEquals(sortedProjects.get(0).getBasedir(), parentPomPath)); String modulePomPath = Path.of(".").resolve("example").toAbsolutePath().normalize().toString(); - assertThat(sortedProjects.get(1).getBasedir().toString()).isEqualTo(modulePomPath); + assertThat(LinuxWindowsPathUnifier.pathEquals(sortedProjects.get(1).getBasedir(), modulePomPath)); } /** @@ -416,11 +444,12 @@ class MavenProjectAnalyzerTest { assertThat(sortedProjects).hasSize(2); - String parentPomPath = Path.of(".").toAbsolutePath().normalize().toString(); - assertThat(sortedProjects.get(0).getBasedir().toString()).isEqualTo(parentPomPath); + String parentPomPath = LinuxWindowsPathUnifier.unifiedPathString(Path.of(".").toAbsolutePath().normalize()); + assertThat(LinuxWindowsPathUnifier.pathEquals(sortedProjects.get(0).getBasedir(), parentPomPath)).isTrue(); - String modulePomPath = Path.of(".").resolve("example").toAbsolutePath().normalize().toString(); - assertThat(sortedProjects.get(1).getBasedir().toString()).isEqualTo(modulePomPath); + String modulePomPath = LinuxWindowsPathUnifier + .unifiedPathString(Path.of(".").resolve("example").toAbsolutePath().normalize()); + assertThat(LinuxWindowsPathUnifier.pathEquals(sortedProjects.get(1).getBasedir(), modulePomPath)).isTrue(); } /** diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializerTest.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializerTest.java index 1567899..188324f 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializerTest.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/parsers/maven/MavenSettingsInitializerTest.java @@ -23,6 +23,7 @@ import org.openrewrite.maven.tree.MavenRepository; import org.sonatype.plexus.components.cipher.PlexusCipherException; import org.springframework.rewrite.parsers.RewriteExecutionContext; import org.springframework.rewrite.scopes.ProjectMetadata; +import org.springframework.rewrite.utils.LinuxWindowsPathUnifier; import java.net.URISyntaxException; import java.nio.file.Path; @@ -57,13 +58,10 @@ class MavenSettingsInitializerTest { MavenRepository localRepository = mavenExecutionContextView.getLocalRepository(); assertThat(localRepository.getSnapshots()).isNull(); - String tmpDir = removeTrailingSlash(System.getProperty("java.io.tmpdir")); - String customLocalRepository = "file://" + Path.of(System.getProperty("user.home")) - .resolve(".m2/repository") - .toAbsolutePath() - .normalize() - .toString();// new URI("file://" + tmpDir).toString(); - assertThat(removeTrailingSlash(localRepository.getUri())).isEqualTo(customLocalRepository); + String expectedCustomLocalRepository = "file://" + LinuxWindowsPathUnifier.unifiedPathString( + Path.of(System.getProperty("user.home")).resolve(".m2/repository").toAbsolutePath().normalize()); + + assertThat(removeTrailingSlash(localRepository.getUri())).isEqualTo(expectedCustomLocalRepository); assertThat(localRepository.getSnapshots()).isNull(); assertThat(localRepository.isKnownToExist()).isTrue(); assertThat(localRepository.getUsername()).isNull(); diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserParityTestHelper.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserParityTestHelper.java index ee0f2b4..fe35f02 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserParityTestHelper.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserParityTestHelper.java @@ -15,6 +15,10 @@ */ package org.springframework.rewrite.test.util; +import org.apache.maven.shared.invoker.DefaultInvocationRequest; +import org.apache.maven.shared.invoker.DefaultInvoker; +import org.apache.maven.shared.invoker.InvocationRequest; +import org.apache.maven.shared.invoker.MavenInvocationException; import org.assertj.core.api.SoftAssertions; import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; @@ -30,8 +34,8 @@ import org.openrewrite.style.Style; import org.springframework.rewrite.parsers.SpringRewriteProperties; import org.springframework.rewrite.parsers.RewriteProjectParsingResult; +import java.io.File; import java.net.URI; -import java.net.URISyntaxException; import java.nio.file.Path; import java.util.*; import java.util.function.BiConsumer; @@ -97,6 +101,8 @@ public class ParserParityTestHelper { RewriteProjectParsingResult expectedParserResult = null; RewriteProjectParsingResult actualParserResult = null; + resolveDependencies(); + ParserExecutionHelper parserExecutionHelper = new ParserExecutionHelper(); if (isParallelParse) { ParallelParsingResult result = parserExecutionHelper.parseParallel(baseDir, springRewriteProperties, @@ -116,6 +122,39 @@ public class ParserParityTestHelper { customParserResultParityChecker.accept(actualParserResult, expectedParserResult); } + private void resolveDependencies() { + try { + DefaultInvoker defaultInvoker = new DefaultInvoker(); + InvocationRequest request = new DefaultInvocationRequest(); + request.setGoals(List.of("clean", "test-compile")); + request.setBaseDirectory(baseDir.toFile()); + // request.setBatchMode(true); + request.setPomFile(baseDir.resolve("pom.xml").toFile()); + + String mavenHome = ""; + if (System.getenv("MAVEN_HOME") != null) { + mavenHome = System.getenv("MAVEN_HOME"); + } + else if (System.getenv("MVN_HOME") != null) { + mavenHome = System.getenv("MVN_HOME"); + } + else if (System.getenv("M2_HOME") != null) { + mavenHome = System.getenv("M2_HOME"); + } + else { + throw new IllegalStateException("Neither MVN_HOME nor MAVEN_HOME set but required by MavenInvoker."); + } + + System.out.println("Using Maven %s".formatted(mavenHome)); + + request.setMavenHome(new File(mavenHome)); + defaultInvoker.execute(request); + } + catch (MavenInvocationException e) { + throw new RuntimeException(e); + } + } + public interface CustomParserResultParityChecker extends BiConsumer { @@ -280,7 +319,7 @@ public class ParserParityTestHelper { .ignoringFields("modules", // checked further down "dependencies", // checked further down "parent.modules" // TODO: - // https://github.com/spring-projects-experimental/spring-boot-migrator/issues/991 + // https://github.com/spring-projects-experimental/spring-boot-migrator/issues/991 ) .ignoringFieldsOfTypes(UUID.class) .isEqualTo(expected); @@ -363,20 +402,18 @@ public class ParserParityTestHelper { && f1.getFragment().equals(f2.getFragment()); } else if (actual instanceof String) { - try { - URI f1 = new URI((String) actual); - URI f2 = new URI((String) expected); - return f1.getScheme() == null ? (f2.getScheme() == null ? true : false) - : f1.getScheme().equals(f2.getScheme()) - && (f1.getHost() == null ? (f2.getHost() == null ? true : false) - : f1.getHost().equals(f2.getHost())) - && f1.getPath().equals(f2.getPath()) && f1.getFragment() == null - ? (f2.getFragment() == null ? true : false) - : f1.getFragment().equals(f2.getFragment()); - } - catch (URISyntaxException e) { - throw new RuntimeException(e); - } + URI f1 = new File((String) actual).toURI(); + URI f2 = new File((String) expected).toURI(); + // @formatter:off + return + f1.getScheme() != null && f2.getScheme() != null ? f1.getScheme().equals(f2.getScheme()) : f1.getScheme() == null && f2.getScheme() == null ? true : false + && + f1.getHost() != null && f2.getHost() != null ? f1.getHost().equals(f2.getHost()) : f1.getHost() == null && f2.getHost() == null ? true : false + && + f1.getPath() != null && f2.getPath() != null ? f1.getPath().equals(f2.getPath()) : f1.getPath() == null && f2.getPath() == null ? true : false + && + f1.getFragment() != null && f2.getFragment() != null ? f1.getFragment().equals(f2.getFragment()) : f1.getFragment() == null && f2.getFragment() == null ? true : false; + // @formatter:on } else { return false;