Skip to content

Commit f23c9fd

Browse files
authored
Improved validation and added support to include incubator modules (elastic#135529)
1 parent b659c3a commit f23c9fd

File tree

4 files changed

+60
-10
lines changed

4 files changed

+60
-10
lines changed

libs/entitlement/tools/common/src/main/java/org/elasticsearch/entitlement/tools/Utils.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121
import java.util.Map;
2222
import java.util.Set;
23+
import java.util.function.Predicate;
2324
import java.util.stream.Collectors;
2425

2526
public class Utils {
@@ -42,6 +43,10 @@ public class Utils {
4243
"jdk.localedata" // noise, change here are not interesting
4344
);
4445

46+
public static final Predicate<String> DEFAULT_MODULE_PREDICATE = m -> EXCLUDED_MODULES.contains(m) == false
47+
&& m.contains(".internal.") == false
48+
&& m.contains(".incubator.") == false;
49+
4550
private static Map<String, Set<String>> findModuleExports(FileSystem fs) throws IOException {
4651
var modulesExports = new HashMap<String, Set<String>>();
4752
try (var stream = Files.walk(fs.getPath("modules"))) {
@@ -69,20 +74,20 @@ public interface JdkModuleConsumer {
6974
}
7075

7176
public static void walkJdkModules(JdkModuleConsumer c) throws IOException {
77+
walkJdkModules(DEFAULT_MODULE_PREDICATE, c);
78+
}
7279

80+
public static void walkJdkModules(Predicate<String> modulePredicate, JdkModuleConsumer c) throws IOException {
7381
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
7482

7583
var moduleExports = Utils.findModuleExports(fs);
76-
7784
try (var stream = Files.walk(fs.getPath("modules"))) {
7885
var modules = stream.filter(x -> x.toString().endsWith(".class"))
7986
.collect(Collectors.groupingBy(x -> x.subpath(1, 2).toString()));
8087

8188
for (var kv : modules.entrySet()) {
8289
var moduleName = kv.getKey();
83-
if (Utils.EXCLUDED_MODULES.contains(moduleName) == false
84-
&& moduleName.contains(".internal.") == false
85-
&& moduleName.contains(".incubator.") == false) {
90+
if (modulePredicate.test(moduleName)) {
8691
var thisModuleExports = moduleExports.get(moduleName);
8792
c.accept(moduleName, kv.getValue(), thisModuleExports);
8893
}

libs/entitlement/tools/jdk-api-extractor/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ Usage example:
1313
diff libs/entitlement/tools/jdk-api-extractor/api-jdk24.tsv libs/entitlement/tools/jdk-api-extractor/api-jdk25.tsv
1414
```
1515

16-
To review the diff of deprecations (by means of `@Deprecated`), use `--deprecations-only` as 2nd argument.
16+
### Optional arguments:
17+
18+
- `--deprecations-only`: reports public deprecations (by means of `@Deprecated`)
19+
- `--include-incubator`: include incubator modules (e.g. `jdk.incubator.vector`)
1720

1821
```bash
1922
./gradlew :libs:entitlement:tools:jdk-api-extractor:run -Druntime.java=24 --args="deprecations-jdk24.tsv --deprecations-only"

libs/entitlement/tools/jdk-api-extractor/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,16 @@ ext {
1616
javaMainClass = "org.elasticsearch.entitlement.tools.jdkapi.JdkApiExtractor"
1717
}
1818

19+
def addIncubatorModules = {
20+
file("${buildParams.runtimeJavaHome.get()}/jmods")
21+
.listFiles()
22+
.findAll { it.name.endsWith('.jmod') && it.name.contains('.incubator.') }
23+
.collectMany { ['--add-modules', it.name[0..-6]] }
24+
}
25+
1926
application {
2027
mainClass.set(javaMainClass)
28+
applicationDefaultJvmArgs = addIncubatorModules()
2129
}
2230

2331
tasks.named("run").configure {

libs/entitlement/tools/jdk-api-extractor/src/main/java/org/elasticsearch/entitlement/tools/jdkapi/JdkApiExtractor.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@
2020
import java.nio.charset.StandardCharsets;
2121
import java.nio.file.Files;
2222
import java.nio.file.Path;
23+
import java.nio.file.Paths;
24+
import java.util.Arrays;
2325
import java.util.Collections;
2426
import java.util.Comparator;
2527
import java.util.Map;
2628
import java.util.Set;
2729
import java.util.TreeMap;
2830
import java.util.TreeSet;
31+
import java.util.function.Predicate;
32+
import java.util.stream.Collectors;
2933
import java.util.stream.Stream;
3034

3135
import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
@@ -49,15 +53,24 @@ public class JdkApiExtractor {
4953
new AccessibleMethod("close", "()V", true, false, true)
5054
);
5155

56+
private static String DEPRECATIONS_ONLY = "--deprecations-only";
57+
private static String INCLUDE_INCUBATOR = "--include-incubator";
58+
59+
private static Set<String> OPTIONAL_ARGS = Set.of(DEPRECATIONS_ONLY, INCLUDE_INCUBATOR);
60+
5261
public static void main(String[] args) throws IOException {
5362
validateArgs(args);
54-
boolean deprecationsOnly = args.length == 2 && args[1].equals("--deprecations-only");
63+
boolean deprecationsOnly = optionalArgs(args).anyMatch(DEPRECATIONS_ONLY::equals);
5564

5665
Map<String, Set<AccessibleMethod>> accessibleImplementationsByClass = new TreeMap<>();
5766
Map<String, Set<AccessibleMethod>> accessibleForOverridesByClass = new TreeMap<>();
5867
Map<String, Set<AccessibleMethod>> deprecationsByClass = new TreeMap<>();
5968

60-
Utils.walkJdkModules((moduleName, moduleClasses, moduleExports) -> {
69+
Predicate<String> modulePredicate = Utils.DEFAULT_MODULE_PREDICATE.or(
70+
m -> optionalArgs(args).anyMatch(INCLUDE_INCUBATOR::equals) && m.contains(".incubator.")
71+
);
72+
73+
Utils.walkJdkModules(modulePredicate, (moduleName, moduleClasses, moduleExports) -> {
6174
var visitor = new AccessibleClassVisitor(
6275
moduleExports,
6376
accessibleImplementationsByClass,
@@ -87,16 +100,37 @@ private static String internalClassName(Path clazz, String moduleName) {
87100
return relativePath.substring(0, relativePath.length() - ".class".length());
88101
}
89102

103+
private static Stream<String> optionalArgs(String[] args) {
104+
return Arrays.stream(args).skip(1);
105+
}
106+
90107
@SuppressForbidden(reason = "cli tool printing to standard err/out")
91108
private static void validateArgs(String[] args) {
92-
boolean valid = args.length == 1 || (args.length == 2 && "--deprecations-only".equals(args[1]));
93-
109+
boolean valid = args.length > 0 && optionalArgs(args).allMatch(OPTIONAL_ARGS::contains);
110+
if (valid && isWritableOutputPath(args[0]) == false) {
111+
valid = false;
112+
System.err.println("invalid output path: " + args[0]);
113+
}
94114
if (valid == false) {
95-
System.err.println("usage: <output file path> [--deprecations-only]");
115+
String optionalArgs = OPTIONAL_ARGS.stream().collect(Collectors.joining("] [", " [", "]"));
116+
System.err.println("usage: <output file path>" + optionalArgs);
96117
System.exit(1);
97118
}
98119
}
99120

121+
private static boolean isWritableOutputPath(String pathStr) {
122+
try {
123+
Path path = Paths.get(pathStr);
124+
if (Files.exists(path) && Files.isRegularFile(path)) {
125+
return Files.isWritable(path);
126+
}
127+
Path parent = path.toAbsolutePath().getParent();
128+
return parent != null && Files.isDirectory(parent) && Files.isWritable(parent);
129+
} catch (Exception e) {
130+
return false;
131+
}
132+
}
133+
100134
@SuppressForbidden(reason = "cli tool printing to standard err/out")
101135
private static void writeFile(Path path, Map<String, Set<AccessibleMethod>> methods) throws IOException {
102136
System.out.println("Writing result for " + Runtime.version() + " to " + path.toAbsolutePath());

0 commit comments

Comments
 (0)