1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.micronaut.build;
17
18 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.fasterxml.jackson.databind.ObjectWriter;
21 import org.apache.maven.model.Resource;
22 import org.apache.maven.plugin.MojoExecutionException;
23 import org.apache.maven.plugins.annotations.Mojo;
24 import org.apache.maven.plugins.annotations.Parameter;
25 import org.apache.maven.plugins.resources.ResourcesMojo;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.*;
33 import java.util.stream.Collectors;
34
35
36
37
38
39
40
41
42 @Mojo(name = GraalVMResourcesMojo.GRAALVM_RESOURCES)
43 public class GraalVMResourcesMojo extends ResourcesMojo {
44
45 public static final String GRAALVM_RESOURCES = "graalvm-resources";
46
47 private static final String META_INF = "META-INF";
48 private static final String RESOURCES = "resources";
49 private static final String PATTERN = "pattern";
50 private static final String RESOURCE_CONFIG_JSON = "resource-config.json";
51 private static final List<String> EXCLUDED_META_INF_DIRECTORIES = Arrays.asList("native-image", "services");
52
53 private final ObjectWriter writer = new ObjectMapper().writer(new DefaultPrettyPrinter());
54
55 @Parameter(property = "micronaut.native-image.skip-resources", defaultValue = "false")
56 private Boolean nativeImageSkipResources;
57
58 @Override
59 public void execute() throws MojoExecutionException {
60 if (Boolean.TRUE.equals(nativeImageSkipResources)) {
61 getLog().info("Skipping generation of resource-config.json");
62 return;
63 }
64
65 Set<String> resourcesToAdd = new HashSet<>();
66
67
68 for (Resource resource : getResources()) {
69 resourcesToAdd.addAll(findResourceFiles(Paths.get(resource.getDirectory()).toFile()));
70 }
71
72
73 Path metaInfPath = getOutputDirectory().toPath().resolve(META_INF);
74 resourcesToAdd.addAll(findResourceFiles(metaInfPath.toFile(), Collections.singletonList(META_INF)));
75
76 Path nativeImagePath = buildNativeImagePath();
77 Path graalVMResourcesPath = metaInfPath.resolve(nativeImagePath).toAbsolutePath();
78
79 Map<String, Object> json = new HashMap<>();
80 List<Map<String, String>> resourceList = resourcesToAdd.stream()
81 .map(this::mapToGraalResource)
82 .collect(Collectors.toList());
83
84 json.put(RESOURCES, resourceList);
85
86 try {
87 Files.createDirectories(graalVMResourcesPath);
88 File resourceConfigFile = graalVMResourcesPath.resolve(RESOURCE_CONFIG_JSON).toFile();
89 getLog().info("Generating " + resourceConfigFile.getAbsolutePath());
90 writer.writeValue(resourceConfigFile, json);
91
92 } catch (IOException e) {
93 throw new MojoExecutionException("There was an error generating GraalVM resource-config.json file", e);
94 }
95 }
96
97 private Set<String> findResourceFiles(File folder) {
98 return this.findResourceFiles(folder, null);
99 }
100
101 private Set<String> findResourceFiles(File folder, List<String> filePath) {
102 Set<String> resourceFiles = new HashSet<>();
103
104 if (filePath == null) {
105 filePath = new ArrayList<>();
106 }
107
108 if (folder.exists()) {
109 File[] files = folder.listFiles();
110
111 if (files != null) {
112 boolean isMetaInfDirectory = folder.getName().equals(META_INF);
113
114 for (File element : files) {
115 boolean isExcludedDirectory = EXCLUDED_META_INF_DIRECTORIES.contains(element.getName());
116
117
118 if (!isMetaInfDirectory || !isExcludedDirectory) {
119 if (element.isDirectory()) {
120 List<String> paths = new ArrayList<>(filePath);
121 paths.add(element.getName());
122
123 resourceFiles.addAll(findResourceFiles(element, paths));
124 } else {
125 String joinedDirectories = String.join("/", filePath);
126 String elementName = joinedDirectories.isEmpty() ? element.getName() : joinedDirectories + "/" + element.getName();
127
128 resourceFiles.add(elementName);
129 }
130 }
131 }
132 }
133 }
134
135 return resourceFiles;
136 }
137
138 private Path buildNativeImagePath() {
139 String group = project.getGroupId();
140 String module = project.getArtifactId();
141
142 return Paths.get("native-image", group, module);
143 }
144
145 private Map<String, String> mapToGraalResource(String resourceName) {
146 Map<String, String> result = new HashMap<>();
147
148 if (resourceName.contains("*")) {
149 result.put(PATTERN, resourceName);
150 } else {
151 result.put(PATTERN, "\\Q" + resourceName + "\\E");
152 }
153
154 return result;
155 }
156 }