001/* 002 * Copyright 2017-2022 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven; 017 018import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; 019import com.fasterxml.jackson.databind.ObjectMapper; 020import com.fasterxml.jackson.databind.ObjectWriter; 021import org.apache.maven.model.Resource; 022import org.apache.maven.plugin.MojoExecutionException; 023import org.apache.maven.plugin.logging.Log; 024import org.apache.maven.plugins.annotations.Mojo; 025import org.apache.maven.plugins.annotations.Parameter; 026import org.apache.maven.plugins.resources.ResourcesMojo; 027 028import java.io.File; 029import java.io.IOException; 030import java.nio.file.Files; 031import java.nio.file.Path; 032import java.nio.file.Paths; 033import java.util.ArrayList; 034import java.util.Arrays; 035import java.util.Collections; 036import java.util.HashMap; 037import java.util.HashSet; 038import java.util.List; 039import java.util.Map; 040import java.util.Set; 041 042/** 043 * <p>Generate GraalVM <code>resources-config.json</code> with all the resources included in the application</p> 044 * <p><strong>WARNING</strong>: this goal is not intended to be executed directly.</p> 045 * 046 * @author Iván López 047 * @since 2.0 048 * @deprecated Please use native:generateResourceConfig and/or native:generateTestResourceConfig instead. 049 */ 050@Mojo(name = GraalVMResourcesMojo.GRAALVM_RESOURCES) 051@Deprecated(since = "4.4.0", forRemoval = true) 052public class GraalVMResourcesMojo extends ResourcesMojo { 053 054 public static final String GRAALVM_RESOURCES = "graalvm-resources"; 055 056 private static final String META_INF = "META-INF"; 057 private static final String RESOURCES = "resources"; 058 private static final String PATTERN = "pattern"; 059 private static final String RESOURCE_CONFIG_JSON = "resource-config.json"; 060 private static final List<String> EXCLUDED_META_INF_DIRECTORIES = Arrays.asList("native-image", "services"); 061 062 private final ObjectWriter writer = new ObjectMapper().writer(new DefaultPrettyPrinter()); 063 064 @Parameter(property = "micronaut.native-image.skip-resources", defaultValue = "false") 065 private Boolean nativeImageSkipResources; 066 067 @Override 068 public void execute() throws MojoExecutionException { 069 if (Boolean.TRUE.equals(nativeImageSkipResources)) { 070 getLog().info("Skipping generation of resource-config.json"); 071 return; 072 } 073 074 var resourcesToAdd = new HashSet<String>(); 075 076 // Application resources (src/main/resources) 077 for (Resource resource : getResources()) { 078 resourcesToAdd.addAll(findResourceFiles(Paths.get(resource.getDirectory()).toFile())); 079 } 080 081 // Generated resources (like openapi) 082 Path metaInfPath = getOutputDirectory().toPath().resolve(META_INF); 083 resourcesToAdd.addAll(findResourceFiles(metaInfPath.toFile(), Collections.singletonList(META_INF))); 084 085 Path nativeImagePath = buildNativeImagePath(); 086 Path graalVMResourcesPath = metaInfPath.resolve(nativeImagePath).toAbsolutePath(); 087 088 var json = new HashMap<String, Object>(); 089 List<Map<String, String>> resourceList = resourcesToAdd.stream() 090 .map(this::mapToGraalResource) 091 .toList(); 092 093 json.put(RESOURCES, resourceList); 094 095 try { 096 Files.createDirectories(graalVMResourcesPath); 097 File resourceConfigFile = graalVMResourcesPath.resolve(RESOURCE_CONFIG_JSON).toFile(); 098 getLog().info("Generating " + resourceConfigFile.getAbsolutePath()); 099 writer.writeValue(resourceConfigFile, json); 100 101 } catch (IOException e) { 102 throw new MojoExecutionException("There was an error generating GraalVM resource-config.json file", e); 103 } 104 } 105 106 private Set<String> findResourceFiles(File folder) { 107 return this.findResourceFiles(folder, null); 108 } 109 110 private Set<String> findResourceFiles(File folder, List<String> filePath) { 111 var resourceFiles = new HashSet<String>(); 112 113 if (filePath == null) { 114 filePath = new ArrayList<>(); 115 } 116 117 if (folder.exists()) { 118 File[] files = folder.listFiles(); 119 120 if (files != null) { 121 boolean isMetaInfDirectory = folder.getName().equals(META_INF); 122 123 for (File element : files) { 124 boolean isExcludedDirectory = EXCLUDED_META_INF_DIRECTORIES.contains(element.getName()); 125 // Exclude some directories in 'META-INF' like 'native-image' and 'services' but process other 126 // 'META-INF' files and directories, for example, to include swagger-ui. 127 if (!isMetaInfDirectory || !isExcludedDirectory) { 128 if (element.isDirectory()) { 129 var paths = new ArrayList<>(filePath); 130 paths.add(element.getName()); 131 132 resourceFiles.addAll(findResourceFiles(element, paths)); 133 } else { 134 String joinedDirectories = String.join("/", filePath); 135 String elementName = joinedDirectories.isEmpty() ? element.getName() : joinedDirectories + "/" + element.getName(); 136 137 resourceFiles.add(elementName); 138 } 139 } 140 } 141 } 142 } 143 144 return resourceFiles; 145 } 146 147 private Path buildNativeImagePath() { 148 String group = project.getGroupId(); 149 String module = project.getArtifactId(); 150 151 return Paths.get("native-image", group, module); 152 } 153 154 private Map<String, String> mapToGraalResource(String resourceName) { 155 var result = new HashMap<String, String>(); 156 157 if (resourceName.contains("*")) { 158 result.put(PATTERN, resourceName); 159 } else { 160 result.put(PATTERN, "\\Q" + resourceName + "\\E"); 161 } 162 163 return result; 164 } 165 166 @Override 167 public void setLog(Log log) { 168 super.setLog(new JansiLog(log)); 169 } 170}