Skip to content

Commit 5f4c870

Browse files
committed
clean up
1 parent 7d7f8cd commit 5f4c870

File tree

2 files changed

+152
-118
lines changed

2 files changed

+152
-118
lines changed

build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java

Lines changed: 147 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,28 @@
2525
import java.io.File;
2626
import java.io.IOException;
2727
import java.io.InputStream;
28-
import java.io.UncheckedIOException;
2928
import java.nio.charset.StandardCharsets;
3029
import java.nio.file.Files;
3130
import java.nio.file.Path;
3231
import java.util.ArrayList;
33-
import java.util.Arrays;
3432
import java.util.HashMap;
3533
import java.util.List;
3634
import java.util.Map;
37-
import java.util.jar.Attributes;
3835
import java.util.jar.JarEntry;
3936
import java.util.jar.JarFile;
4037
import java.util.jar.Manifest;
4138
import java.util.regex.Matcher;
4239
import java.util.regex.Pattern;
40+
import java.util.zip.ZipEntry;
4341

42+
/**
43+
* This task generates a file with a class to module mapping
44+
* used to imitate modular behavior during unit tests so
45+
* entitlements can lookup correct policies.
46+
*/
4447
public abstract class GenerateTestBuildInfoTask extends DefaultTask {
4548

4649
public static final String DESCRIPTION = "generates plugin test dependencies file";
47-
public static final String PROPERTIES_FILENAME = "test-build-info.json";
4850

4951
public GenerateTestBuildInfoTask() {
5052
setDescription(DESCRIPTION);
@@ -64,120 +66,7 @@ public GenerateTestBuildInfoTask() {
6466

6567
@TaskAction
6668
public void generatePropertiesFile() throws IOException {
67-
Map<String, String> classesToModules = new HashMap<>();
68-
for (File file : getCodeLocations().get().getFiles()) {
69-
if (file.exists()) {
70-
if (file.getName().endsWith(".jar")) {
71-
try (JarFile jarFile = new JarFile(file)) {
72-
String[] moduleName = new String[1];
73-
JarEntry moduleEntry = jarFile.getJarEntry("module-info.class");
74-
if (moduleEntry != null) {
75-
try (InputStream miis = jarFile.getInputStream(moduleEntry)) {
76-
ClassReader cr = new ClassReader(miis);
77-
cr.accept(new ClassVisitor(Opcodes.ASM9) {
78-
@Override
79-
public ModuleVisitor visitModule(String name, int access, String version) {
80-
// getLogger().lifecycle("FOUND 0: " + name + " | " + file.getAbsolutePath());
81-
moduleName[0] = name;
82-
return super.visitModule(name, access, version);
83-
}
84-
}, Opcodes.ASM9);
85-
}
86-
} else {
87-
moduleEntry = jarFile.getJarEntry("META-INF/MANIFEST.MF");
88-
if (moduleEntry != null) {
89-
try (InputStream meis = jarFile.getInputStream(moduleEntry)) {
90-
Manifest manifest = new Manifest(meis);
91-
String mr = manifest.getMainAttributes().getValue(Attributes.Name.MULTI_RELEASE);
92-
if (Boolean.parseBoolean(mr)) {
93-
List<Integer> versions = jarFile.stream()
94-
.filter(
95-
je -> je.getName().startsWith("META-INF/versions/")
96-
&& je.getName().endsWith("/module-info.class")
97-
)
98-
.map(je -> Integer.parseInt(je.getName().substring(18, je.getName().length() - 18)))
99-
.toList();
100-
versions = new ArrayList<>(versions);
101-
versions.sort(Integer::compareTo);
102-
versions = versions.reversed();
103-
int major = Runtime.version().version().get(0);
104-
StringBuilder path = new StringBuilder("META-INF/versions/");
105-
for (int version : versions) {
106-
if (version <= major) {
107-
path.append(version);
108-
break;
109-
}
110-
}
111-
if (path.length() > 18) {
112-
path.append("/module-info.class");
113-
moduleEntry = jarFile.getJarEntry(path.toString());
114-
if (moduleEntry != null) {
115-
try (InputStream miis = jarFile.getInputStream(moduleEntry)) {
116-
ClassReader cr = new ClassReader(miis);
117-
cr.accept(new ClassVisitor(Opcodes.ASM9) {
118-
@Override
119-
public ModuleVisitor visitModule(String name, int access, String version) {
120-
// getLogger().lifecycle("FOUND 1: " + name + " | " + file.getAbsolutePath());
121-
moduleName[0] = name;
122-
return super.visitModule(name, access, version);
123-
}
124-
}, Opcodes.ASM9);
125-
}
126-
}
127-
}
128-
}
129-
if (moduleName[0] == null) {
130-
String amn = manifest.getMainAttributes().getValue("Automatic-Module-Name");
131-
if (amn != null) {
132-
// getLogger().lifecycle("FOUND 2: " + amn + " | " + file.getAbsolutePath());
133-
moduleName[0] = amn;
134-
}
135-
}
136-
}
137-
}
138-
if (moduleName[0] == null) {
139-
String jn = file.getName().substring(0, file.getName().length() - 4);
140-
Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(jn);
141-
if (matcher.find()) {
142-
jn = jn.substring(0, matcher.start());
143-
}
144-
jn = jn.replaceAll("[^A-Za-z0-9]", ".");
145-
// getLogger().lifecycle("FOUND 3: " + jn + " | " + file.getAbsolutePath());
146-
moduleName[0] = jn;
147-
}
148-
}
149-
jarFile.stream()
150-
.filter(
151-
je -> je.getName().startsWith("META-INF") == false
152-
&& je.getName().equals("module-info.class") == false
153-
&& je.getName().endsWith(".class")
154-
)
155-
.findFirst()
156-
.ifPresent(je -> classesToModules.put(je.getName(), moduleName[0]));
157-
} catch (IOException ioe) {
158-
throw new UncheckedIOException(ioe);
159-
}
160-
} else if (file.isDirectory()) {
161-
List<File> files = new ArrayList<>(List.of(file));
162-
while (files.isEmpty() == false) {
163-
File find = files.removeFirst();
164-
if (find.exists()) {
165-
if (find.isDirectory() && find.getName().equals("META_INF") == false) {
166-
files.addAll(Arrays.asList(find.listFiles()));
167-
} else if (find.getName().equals("module-info.class") == false && find.getName().contains("$") == false) {
168-
classesToModules.put(
169-
find.getAbsolutePath().substring(file.getAbsolutePath().length() + 1),
170-
"module-goes-here"
171-
);
172-
break;
173-
}
174-
}
175-
}
176-
} else {
177-
throw new IllegalArgumentException("Unrecognized classpath file: " + file);
178-
}
179-
}
180-
}
69+
Map<String, String> classesToModules = buildClassesToModules();
18170

18271
Path outputDirectory = getOutputDirectory().get().getAsFile().toPath();
18372
Files.createDirectories(outputDirectory);
@@ -206,4 +95,144 @@ public ModuleVisitor visitModule(String name, int access, String version) {
20695
writer.write("\n ]\n}\n");
20796
}
20897
}
98+
99+
private Map<String, String> buildClassesToModules() throws IOException {
100+
Map<String, String> classesToModules = new HashMap<>();
101+
for (File file : getCodeLocations().get().getFiles()) {
102+
if (file.exists()) {
103+
if (file.getName().endsWith(".jar")) {
104+
extractFromJar(file, classesToModules);
105+
} else if (file.isDirectory()) {
106+
extractFromDirectory(file, classesToModules);
107+
} else {
108+
throw new IllegalArgumentException("unrecognized classpath entry: " + file);
109+
}
110+
}
111+
}
112+
return classesToModules;
113+
}
114+
115+
private void extractFromJar(File file, Map<String, String> classesToModules) throws IOException {
116+
try (JarFile jarFile = new JarFile(file)) {
117+
String className = extractClassNameFromJar(jarFile);
118+
String moduleName = extractModuleNameFromJar(file, jarFile);
119+
120+
if (className != null) {
121+
classesToModules.put(className, moduleName);
122+
}
123+
}
124+
}
125+
126+
private String extractClassNameFromJar(JarFile jarFile) {
127+
return jarFile.stream()
128+
.filter(
129+
je -> je.getName().startsWith("META-INF") == false
130+
&& je.getName().equals("module-info.class") == false
131+
&& je.getName().endsWith(".class")
132+
)
133+
.findFirst().map(ZipEntry::getName).orElse(null);
134+
}
135+
136+
private String extractModuleNameFromJar(File file, JarFile jarFile) throws IOException {
137+
String moduleName = null;
138+
139+
if (jarFile.isMultiRelease()) {
140+
List<Integer> versions = jarFile.stream()
141+
.filter(
142+
je -> je.getName().startsWith("META-INF/versions/")
143+
&& je.getName().endsWith("/module-info.class")
144+
)
145+
.map(je -> Integer.parseInt(je.getName().substring(18, je.getName().length() - 18)))
146+
.toList();
147+
versions = new ArrayList<>(versions);
148+
versions.sort(Integer::compareTo);
149+
versions = versions.reversed();
150+
int major = Runtime.version().version().get(0);
151+
StringBuilder path = new StringBuilder("META-INF/versions/");
152+
for (int version : versions) {
153+
if (version <= major) {
154+
path.append(version);
155+
break;
156+
}
157+
}
158+
if (path.length() > 18) {
159+
path.append("/module-info.class");
160+
JarEntry moduleEntry = jarFile.getJarEntry(path.toString());
161+
if (moduleEntry != null) {
162+
try (InputStream inputStream = jarFile.getInputStream(moduleEntry)) {
163+
moduleName = extractModuleNameFromModuleInfo(inputStream);
164+
}
165+
}
166+
}
167+
}
168+
169+
if (moduleName == null) {
170+
JarEntry moduleEntry = jarFile.getJarEntry("module-info.class");
171+
if (moduleEntry != null) {
172+
try (InputStream inputStream = jarFile.getInputStream(moduleEntry)) {
173+
moduleName = extractModuleNameFromModuleInfo(inputStream);
174+
}
175+
}
176+
}
177+
178+
if (moduleName == null) {
179+
JarEntry manifestEntry = jarFile.getJarEntry("META-INF/MANIFEST.MF");
180+
if (manifestEntry != null) {
181+
try (InputStream inputStream = jarFile.getInputStream(manifestEntry)) {
182+
Manifest manifest = new Manifest(inputStream);
183+
String amn = manifest.getMainAttributes().getValue("Automatic-Module-Name");
184+
if (amn != null) {
185+
moduleName = amn;
186+
}
187+
}
188+
}
189+
}
190+
191+
if (moduleName == null) {
192+
String jn = file.getName().substring(0, file.getName().length() - 4);
193+
Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(jn);
194+
if (matcher.find()) {
195+
jn = jn.substring(0, matcher.start());
196+
}
197+
jn = jn.replaceAll("[^A-Za-z0-9]", ".");
198+
moduleName = jn;
199+
}
200+
201+
return moduleName;
202+
}
203+
204+
private void extractFromDirectory(File file, Map<String, String> classesToModules) {
205+
String className = extractClassNameFromDirectory(file);
206+
String moduleName = null;
207+
208+
if (className != null && moduleName != null) {
209+
classesToModules.put(className, moduleName);
210+
}
211+
}
212+
213+
private String extractClassNameFromDirectory(File file) {
214+
List<File> files = new ArrayList<>(List.of(file));
215+
while (files.isEmpty() == false) {
216+
File find = files.removeFirst();
217+
if (find.exists()) {
218+
if (find.getName().endsWith(".class") && find.getName().equals("module-info.class") == false && find.getName().contains("$") == false) {
219+
return find.getAbsolutePath().substring(file.getAbsolutePath().length() + 1);
220+
}
221+
}
222+
}
223+
return null;
224+
}
225+
226+
private String extractModuleNameFromModuleInfo(InputStream inputStream) throws IOException {
227+
String[] moduleName = new String[1];
228+
ClassReader cr = new ClassReader(inputStream);
229+
cr.accept(new ClassVisitor(Opcodes.ASM9) {
230+
@Override
231+
public ModuleVisitor visitModule(String name, int access, String version) {
232+
moduleName[0] = name;
233+
return super.visitModule(name, access, version);
234+
}
235+
}, Opcodes.ASM9);
236+
return moduleName[0];
237+
}
209238
}

build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222

2323
import javax.inject.Inject;
2424

25+
/**
26+
* This plugin configures the {@link GenerateTestBuildInfoTask} task
27+
* with customizations for component name and output file name coming
28+
* from the source using the plugin (server or ES plugin).
29+
*/
2530
public class TestBuildInfoPlugin implements Plugin<Project> {
2631

2732
protected final ProviderFactory providerFactory;

0 commit comments

Comments
 (0)