diff --git a/build-tools/src/integTest/groovy/org/elasticsearch/gradle/test/TestBuildInfoPluginFuncTest.groovy b/build-tools/src/integTest/groovy/org/elasticsearch/gradle/test/TestBuildInfoPluginFuncTest.groovy index 56c5e6b59e8d3..a652deb726d1d 100644 --- a/build-tools/src/integTest/groovy/org/elasticsearch/gradle/test/TestBuildInfoPluginFuncTest.groovy +++ b/build-tools/src/integTest/groovy/org/elasticsearch/gradle/test/TestBuildInfoPluginFuncTest.groovy @@ -5,10 +5,8 @@ import com.fasterxml.jackson.databind.ObjectMapper import org.elasticsearch.gradle.fixtures.AbstractGradleFuncTest import org.gradle.testkit.runner.TaskOutcome -import java.nio.file.Path - class TestBuildInfoPluginFuncTest extends AbstractGradleFuncTest { - def "works"() { + def "basic functionality"() { given: file("src/main/java/com/example/Example.java") << """ package com.example; @@ -54,7 +52,7 @@ class TestBuildInfoPluginFuncTest extends AbstractGradleFuncTest { def location = Map.of( "module", "com.example", - "representative_class", Path.of("com", "example", "Example.class").toString() + "representative_class", "com/example/Example.class" ) def expectedOutput = Map.of( "component", "example-component", @@ -62,4 +60,62 @@ class TestBuildInfoPluginFuncTest extends AbstractGradleFuncTest { ) new ObjectMapper().readValue(output, Map.class) == expectedOutput } + + def "dependencies"() { + buildFile << """ + import org.elasticsearch.gradle.plugin.GenerateTestBuildInfoTask; + + plugins { + id 'java' + id 'elasticsearch.test-build-info' + } + + repositories { + mavenCentral() + } + + dependencies { + // We pin to specific versions here because they are known to have the properties we want to test. + // We're not actually running this code. + implementation "org.ow2.asm:asm:9.7.1" // has module-info.class + implementation "junit:junit:4.13" // has Automatic-Module-Name, and brings in hamcrest which does not + } + + tasks.withType(GenerateTestBuildInfoTask.class) { + componentName = 'example-component' + outputFile = new File('build/generated-build-info/plugin-test-build-info.json') + } + """ + + when: + def result = gradleRunner('generateTestBuildInfo').build() + def task = result.task(":generateTestBuildInfo") + + + then: + task.outcome == TaskOutcome.SUCCESS + + def output = file("build/generated-build-info/plugin-test-build-info.json") + output.exists() == true + + def locationFromModuleInfo = Map.of( + "module", "org.objectweb.asm", + "representative_class", 'org/objectweb/asm/AnnotationVisitor.class' + ) + def locationFromManifest = Map.of( + "module", "junit", + "representative_class", 'junit/textui/TestRunner.class' + ) + def locationFromJarFileName = Map.of( + "module", "hamcrest.core", + "representative_class", 'org/hamcrest/BaseDescription.class' + ) + def expectedOutput = Map.of( + "component", "example-component", + "locations", List.of(locationFromModuleInfo, locationFromManifest, locationFromJarFileName) + ) + + def value = new ObjectMapper().readValue(output, Map.class) + value == expectedOutput + } } diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java b/build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java index c0f9eda18b21a..f015942eb7152 100644 --- a/build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java +++ b/build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java @@ -41,7 +41,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.security.CodeSource; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -209,6 +209,7 @@ private String extractModuleNameFromJar(File file, JarFile jarFile) throws IOExc * @return a {@link StringBuilder} with the {@code META-INF/versions/} if it exists; otherwise null */ private static StringBuilder versionDirectoryIfExists(JarFile jarFile) { + Comparator numericOrder = Integer::compareTo; List versions = jarFile.stream() .filter(je -> je.getName().startsWith(META_INF_VERSIONS_PREFIX) && je.getName().endsWith("/module-info.class")) .map( @@ -216,10 +217,8 @@ private static StringBuilder versionDirectoryIfExists(JarFile jarFile) { je.getName().substring(META_INF_VERSIONS_PREFIX.length(), je.getName().length() - META_INF_VERSIONS_PREFIX.length()) ) ) + .sorted(numericOrder.reversed()) .toList(); - versions = new ArrayList<>(versions); - versions.sort(Integer::compareTo); - versions = versions.reversed(); int major = Runtime.version().feature(); StringBuilder path = new StringBuilder(META_INF_VERSIONS_PREFIX); for (int version : versions) { @@ -300,7 +299,10 @@ private String extractClassNameFromDirectory(File dir) throws IOException { public @NotNull FileVisitResult visitFile(@NotNull Path candidate, @NotNull BasicFileAttributes attrs) { String name = candidate.getFileName().toString(); // Just the part after the last dir separator if (name.endsWith(".class") && (name.equals("module-info.class") || name.contains("$")) == false) { - result = candidate.toAbsolutePath().toString().substring(dir.getAbsolutePath().length() + 1); + result = candidate.toAbsolutePath() + .toString() + .substring(dir.getAbsolutePath().length() + 1) + .replace(File.separatorChar, '/'); return TERMINATE; } else { return CONTINUE; @@ -316,20 +318,24 @@ private String extractClassNameFromDirectory(File dir) throws IOException { * if it exists or the preset one derived from the jar task */ private String extractModuleNameFromDirectory(File dir) throws IOException { - List files = new ArrayList<>(List.of(dir)); - while (files.isEmpty() == false) { - File find = files.removeFirst(); - if (find.exists()) { - if (find.getName().equals("module-info.class")) { - try (InputStream inputStream = new FileInputStream(find)) { - return extractModuleNameFromModuleInfo(inputStream); + var visitor = new SimpleFileVisitor() { + private String result = getModuleName().getOrNull(); + + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path candidate, @NotNull BasicFileAttributes attrs) throws IOException { + String name = candidate.getFileName().toString(); // Just the part after the last dir separator + if (name.equals("module-info.class")) { + try (InputStream inputStream = new FileInputStream(candidate.toFile())) { + result = extractModuleNameFromModuleInfo(inputStream); + return TERMINATE; } - } else if (find.isDirectory()) { - files.addAll(Arrays.asList(find.listFiles())); + } else { + return CONTINUE; } } - } - return getModuleName().getOrNull(); + }; + Files.walkFileTree(dir.toPath(), visitor); + return visitor.result; } /**