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.aot; 017 018import io.micronaut.aot.std.sourcegen.AbstractStaticServiceLoaderSourceGenerator; 019import io.micronaut.aot.std.sourcegen.KnownMissingTypesSourceGenerator; 020import io.micronaut.maven.services.CompilerService; 021import io.micronaut.maven.services.DependencyResolutionService; 022import io.micronaut.maven.services.ExecutorService; 023import org.apache.commons.io.FileUtils; 024import org.apache.maven.execution.MavenSession; 025import org.apache.maven.plugin.MojoExecutionException; 026import org.apache.maven.plugins.annotations.Mojo; 027import org.apache.maven.plugins.annotations.Parameter; 028import org.apache.maven.plugins.annotations.ResolutionScope; 029import org.apache.maven.project.MavenProject; 030import org.apache.maven.toolchain.ToolchainManager; 031 032import javax.inject.Inject; 033import java.io.File; 034import java.io.IOException; 035import java.io.InputStream; 036import java.io.OutputStream; 037import java.nio.file.Files; 038import java.nio.file.NoSuchFileException; 039import java.nio.file.Path; 040import java.util.ArrayList; 041import java.util.List; 042import java.util.Properties; 043import java.util.stream.Stream; 044 045/** 046 * <p>Invokes the <a href="https://micronaut-projects.github.io/micronaut-aot/latest/guide/">Micronaut AOT</a> 047 * optimizer, generating sources/classes and the effective AOT configuration properties file. Refer to the Micronaut 048 * AOT documentation for more information.</p> 049 * 050 * <p><strong>WARNING</strong>: this goal is not intended to be executed directly. Instead, enable AOT with the 051 * <code>micronaut.aot.enabled</code> property, eg:</p> 052 * 053 * <pre>mvn -Dmicronaut.aot.enabled=true package</pre> 054 * <pre>mvn -Dmicronaut.aot.enabled=true mn:run</pre> 055 */ 056@Mojo(name = AotAnalysisMojo.NAME, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) 057public class AotAnalysisMojo extends AbstractMicronautAotCliMojo { 058 059 public static final String NAME = "aot-analysis"; 060 public static final String AOT_PROPERTIES_FILE_NAME = "aot.properties"; 061 062 /** 063 * The project's target directory. 064 */ 065 @Parameter(defaultValue = "${project.build.directory}", required = true) 066 private File baseDirectory; 067 068 /** 069 * Micronaut AOT configuration file. Run the <a href="aot-sample-config-mojo.html"><code>aot-sample-config</code> goal</a> to 070 * see all the possible options. 071 */ 072 @Parameter(property = "micronaut.aot.config", defaultValue = AOT_PROPERTIES_FILE_NAME) 073 private File configFile; 074 075 @Inject 076 @SuppressWarnings("CdiInjectionPointsInspection") 077 public AotAnalysisMojo(CompilerService compilerService, ExecutorService executorService, MavenProject mavenProject, 078 DependencyResolutionService dependencyResolutionService, 079 MavenSession mavenSession, ToolchainManager toolchainManager) { 080 super(compilerService, executorService, mavenProject, dependencyResolutionService, mavenSession, toolchainManager); 081 } 082 083 @Override 084 protected List<String> getExtraArgs() throws MojoExecutionException { 085 var args = new ArrayList<String>(); 086 args.add("--output"); 087 File generated = outputFile("generated"); 088 args.add(generated.getAbsolutePath()); 089 File effectiveConfigFile = writeEffectiveConfigFile(); 090 args.add("--config"); 091 args.add(effectiveConfigFile.getAbsolutePath()); 092 return args; 093 } 094 095 private File writeEffectiveConfigFile() throws MojoExecutionException { 096 File userProvidedFile = this.configFile == null ? new File(baseDirectory, AOT_PROPERTIES_FILE_NAME) : this.configFile; 097 var props = new Properties(); 098 if (userProvidedFile.exists()) { 099 try (InputStream in = Files.newInputStream(userProvidedFile.toPath())) { 100 getLog().info("Using AOT configuration file: " + configFile.getAbsolutePath()); 101 props.load(in); 102 } catch (IOException e) { 103 throw new MojoExecutionException("Unable to parse configuration file", e); 104 } 105 } 106 if (!props.containsKey(KnownMissingTypesSourceGenerator.OPTION.key())) { 107 props.put(KnownMissingTypesSourceGenerator.OPTION.key(), String.join(",", Constants.TYPES_TO_CHECK)); 108 } 109 props.computeIfAbsent(AbstractStaticServiceLoaderSourceGenerator.SERVICE_TYPES, 110 key -> String.join(",", Constants.SERVICE_TYPES)); 111 File effectiveConfig = outputFile("effective-" + AOT_PROPERTIES_FILE_NAME); 112 try (OutputStream out = Files.newOutputStream(effectiveConfig.toPath())) { 113 props.store(out, "Effective AOT configuration"); 114 } catch (IOException e) { 115 throw new MojoExecutionException("Unable to parse configuration file", e); 116 } 117 return effectiveConfig; 118 } 119 120 @Override 121 protected void onSuccess(File outputDir) throws MojoExecutionException { 122 Path generated = outputDir.toPath().resolve("generated"); 123 Path generatedClasses = generated.resolve("classes"); 124 try { 125 FileUtils.copyDirectory(generatedClasses.toFile(), outputDirectory); 126 try (Stream<String> linesStream = Files.lines(generated.resolve("logs").resolve("resource-filter.txt"))) { 127 linesStream.forEach(toRemove -> { 128 try { 129 Files.delete(outputDirectory.toPath().resolve(toRemove)); 130 getLog().debug("Removed " + toRemove); 131 } catch (IOException e) { 132 if (!(e instanceof NoSuchFileException)) { 133 getLog().warn("Error while deleting " + toRemove, e); 134 } 135 } 136 }); 137 } 138 } catch (IOException e) { 139 throw new MojoExecutionException("Error when copying the Micronaut AOT generated classes into the target directory", e); 140 } 141 } 142 143 @Override 144 String getName() { 145 return NAME; 146 } 147}