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.maven.JansiLog; 019import io.micronaut.maven.aot.internal.AotPackaging; 020import io.micronaut.maven.services.CompilerService; 021import org.apache.commons.io.FileUtils; 022import org.apache.maven.model.Exclusion; 023import org.apache.maven.plugin.AbstractMojo; 024import org.apache.maven.plugin.MojoExecutionException; 025import org.apache.maven.plugin.logging.Log; 026import org.apache.maven.plugins.annotations.Parameter; 027import org.apache.maven.project.MavenProject; 028import org.eclipse.aether.resolution.DependencyResolutionException; 029 030import java.io.File; 031import java.io.IOException; 032import java.util.List; 033 034/** 035 * Abstract Mojo for Micronaut AOT. 036 * 037 * @author Álvaro Sánchez-Mariscal 038 * @since 3.2.0 039 */ 040public abstract class AbstractMicronautAotMojo extends AbstractMojo { 041 042 protected final CompilerService compilerService; 043 protected final MavenProject mavenProject; 044 045 /** 046 * Micronaut AOT runtime. Possible values: <code>jit</code>, <code>native</code>. 047 */ 048 @Parameter(property = "micronaut.aot.runtime", required = true, defaultValue = "jit") 049 protected String runtime; 050 051 /** 052 * Micronaut AOT version. 053 */ 054 @Parameter(property = "micronaut.aot.version", required = true) 055 protected String micronautAotVersion; 056 057 /** 058 * Whether to enable or disable Micronaut AOT. 059 */ 060 @Parameter(property = "micronaut.aot.enabled", defaultValue = "false") 061 protected boolean enabled; 062 063 /** 064 * Directory where compiled application classes are. 065 */ 066 @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) 067 protected File outputDirectory; 068 069 /** 070 * Packages that would be excluded from the AOT processing. 071 * 072 * @since 4.11.0 073 */ 074 @Parameter(property = "exclusions") 075 protected List<Exclusion> aotExclusions; 076 077 protected AbstractMicronautAotMojo(CompilerService compilerService, MavenProject mavenProject) { 078 this.compilerService = compilerService; 079 this.mavenProject = mavenProject; 080 } 081 082 @Override 083 public void setLog(Log log) { 084 super.setLog(new JansiLog(log)); 085 } 086 087 protected final File getBaseOutputDirectory() { 088 File targetDirectory = new File(mavenProject.getBuild().getDirectory(), "aot"); 089 return new File(targetDirectory, runtime); 090 } 091 092 protected final File outputFile(String name) { 093 return new File(getBaseOutputDirectory(), name); 094 } 095 096 @Override 097 public final void execute() throws MojoExecutionException { 098 if (!enabled || !shouldExecute()) { 099 return; 100 } 101 if (alignRuntimeWithPackaging()) { 102 validateRuntime(); 103 } 104 getLog().info("Running Micronaut AOT " + micronautAotVersion + " " + getName()); 105 try { 106 File baseOutputDirectory = getBaseOutputDirectory(); 107 clean(baseOutputDirectory); 108 clean(outputDirectory); 109 doExecute(); 110 onSuccess(baseOutputDirectory); 111 } catch (DependencyResolutionException | IOException e) { 112 throw new MojoExecutionException("Unable to generate AOT optimizations", e); 113 } 114 } 115 116 /** 117 * Allows concrete plugins to suppress execution for specific project layouts. 118 * 119 * @return {@code true} when AOT execution should proceed 120 */ 121 protected boolean shouldExecute() { 122 return true; 123 } 124 125 /** 126 * Controls whether the configured runtime should be normalized against the current project packaging. 127 * 128 * @return {@code true} to enforce the integrated packaging/runtime mapping 129 */ 130 protected boolean alignRuntimeWithPackaging() { 131 return true; 132 } 133 134 abstract void onSuccess(File outputDir) throws MojoExecutionException; 135 136 protected abstract void doExecute() throws DependencyResolutionException, MojoExecutionException; 137 138 abstract String getName(); 139 140 private void clean(File directory) throws IOException { 141 if (directory.exists()) { 142 getLog().debug("Deleting " + directory.getAbsolutePath()); 143 FileUtils.deleteDirectory(directory); 144 } 145 directory.mkdirs(); 146 } 147 148 private void validateRuntime() { 149 String packagingId = mavenProject.getPackaging(); 150 AotPackaging packaging = AotPackaging.find(packagingId).orElse(null); 151 if (packaging == null) { 152 getLog().debug("Skipping AOT runtime alignment for unsupported packaging: " + packagingId); 153 return; 154 } 155 AotRuntime aotRuntime = AotRuntime.valueOf(runtime.toUpperCase()); 156 switch (packaging) { 157 case JAR, DOCKER, DOCKER_CRAC, K8S, OPENSHIFT -> { 158 if (aotRuntime != AotRuntime.JIT) { 159 warnRuntimeMismatchAndSetCorrectValue(AotRuntime.JIT); 160 } 161 } 162 case NATIVE_IMAGE, DOCKER_NATIVE -> { 163 if (aotRuntime != AotRuntime.NATIVE) { 164 warnRuntimeMismatchAndSetCorrectValue(AotRuntime.NATIVE); 165 } 166 } 167 default -> { 168 // No additional runtime normalization is required. 169 } 170 } 171 } 172 173 private void warnRuntimeMismatchAndSetCorrectValue(AotRuntime correctRuntime) { 174 String correctRuntimeString = correctRuntime.name().toLowerCase(); 175 getLog().warn("Packaging is set to [" + mavenProject.getPackaging() + "], but Micronaut AOT runtime is set to [" + runtime + "]. Setting AOT runtime to: [" + correctRuntimeString + "]"); 176 runtime = correctRuntimeString; 177 } 178}