1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.micronaut.build.aot;
17
18 import io.micronaut.build.services.CompilerService;
19 import io.micronaut.build.services.DependencyResolutionService;
20 import io.micronaut.build.services.ExecutorService;
21 import org.apache.maven.execution.MavenSession;
22 import org.apache.maven.plugin.MojoExecutionException;
23 import org.apache.maven.plugins.annotations.Parameter;
24 import org.apache.maven.project.MavenProject;
25 import org.apache.maven.shared.invoker.InvocationResult;
26 import org.apache.maven.shared.invoker.MavenInvocationException;
27 import org.codehaus.plexus.util.StringUtils;
28 import org.codehaus.plexus.util.xml.Xpp3Dom;
29 import org.eclipse.aether.RepositorySystem;
30 import org.eclipse.aether.artifact.Artifact;
31 import org.eclipse.aether.artifact.DefaultArtifact;
32 import org.eclipse.aether.resolution.DependencyResolutionException;
33 import org.eclipse.aether.util.artifact.JavaScopes;
34 import org.twdata.maven.mojoexecutor.MojoExecutor;
35
36 import javax.inject.Inject;
37 import java.io.File;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.stream.Stream;
43
44 import static io.micronaut.build.aot.Constants.*;
45 import static io.micronaut.build.services.DependencyResolutionService.toClasspath;
46 import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
47 import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
48
49
50
51
52 public abstract class AbstractMicronautAotCliMojo extends AbstractMicronautAotMojo {
53
54 public static final String EXEC_MAVEN_PLUGIN_GROUP = "org.codehaus.mojo";
55 public static final String EXEC_MAVEN_PLUGIN_ARTIFACT = "exec-maven-plugin";
56 public static final String EXEC_MAVEN_PLUGIN_VERSION_PROPERTY = "exec-maven-plugin.version";
57 public static final String DEFAULT_EXEC_MAVEN_PLUGIN_VERSION = "3.0.0";
58
59 private static final String[] AOT_MODULES = new String[]{
60 "api",
61 "cli",
62 "std-optimizers"
63 };
64
65
66
67
68 @Parameter(property = MICRONAUT_AOT_PACKAGE_NAME)
69 protected String packageName;
70
71 private final ExecutorService executorService;
72
73 private final DependencyResolutionService dependencyResolutionService;
74
75 @Parameter
76 private List<org.apache.maven.model.Dependency> aotDependencies;
77
78 @Inject
79 public AbstractMicronautAotCliMojo(CompilerService compilerService, ExecutorService executorService,
80 MavenProject mavenProject, MavenSession mavenSession,
81 RepositorySystem repositorySystem, DependencyResolutionService dependencyResolutionService) {
82 super(compilerService, mavenProject, mavenSession, repositorySystem);
83 this.executorService = executorService;
84 this.dependencyResolutionService = dependencyResolutionService;
85 }
86
87 protected abstract List<String> getExtraArgs() throws MojoExecutionException;
88
89 @Override
90 protected void doExecute() throws MojoExecutionException, DependencyResolutionException {
91 if (StringUtils.isEmpty(packageName)) {
92 throw new MojoExecutionException(MICRONAUT_AOT_PACKAGE_NAME + " is not set, and is required if AOT is enabled");
93 }
94 try {
95 getLog().info("Packaging project");
96 compilerService.compileProject(true);
97 InvocationResult packagingResult = compilerService.packageProject();
98 if (packagingResult.getExitCode() != 0) {
99 getLog().error("Error when packaging the project: ", packagingResult.getExecutionException());
100 } else {
101 executeAot();
102 }
103 } catch (MavenInvocationException e) {
104 getLog().error("Error when packaging project", e);
105 }
106 }
107
108 private void executeAot() throws DependencyResolutionException, MojoExecutionException {
109 getLog().info("Executing Micronaut AOT analysis");
110 Xpp3Dom config = createExecPluginConfig();
111
112 executorService.executeGoal(
113 EXEC_MAVEN_PLUGIN_GROUP,
114 EXEC_MAVEN_PLUGIN_ARTIFACT,
115 mavenProject.getProperties().getProperty(EXEC_MAVEN_PLUGIN_VERSION_PROPERTY, DEFAULT_EXEC_MAVEN_PLUGIN_VERSION),
116 "exec",
117 config
118 );
119 }
120
121 private Xpp3Dom createExecPluginConfig() throws DependencyResolutionException, MojoExecutionException {
122 List<String> aotClasspath = resolveAotClasspath();
123 List<String> aotPluginsClasspath = resolveAotPluginsClasspath();
124 List<String> applicationClasspath = resolveApplicationClasspath();
125
126 List<String> classpath = new ArrayList<>(aotPluginsClasspath.size() + applicationClasspath.size());
127 classpath.addAll(aotClasspath);
128 classpath.addAll(aotPluginsClasspath);
129 classpath.addAll(applicationClasspath);
130 MojoExecutor.Element[] runnerArgs = Stream.concat(Stream.of(
131 "-classpath",
132 String.join(File.pathSeparator, aotClasspath),
133 MICRONAUT_AOT_MAIN_CLASS,
134
135
136 "--classpath=" + String.join(File.pathSeparator, classpath),
137 "--package=" + packageName,
138 "--runtime=" + runtime
139 ), getExtraArgs().stream())
140 .map(arg -> element("argument", arg))
141 .toArray(MojoExecutor.Element[]::new);
142 return configuration(
143 element("executable", "java"),
144 element("arguments", runnerArgs)
145 );
146 }
147
148 private List<String> resolveApplicationClasspath() {
149 String projectJar = new File(mavenProject.getBuild().getDirectory(), mavenProject.getBuild().getFinalName() + ".jar").getAbsolutePath();
150 List<String> result = new ArrayList<>();
151 result.add(projectJar);
152 String classpath = compilerService.buildClasspath(compilerService.resolveDependencies(JavaScopes.RUNTIME));
153 result.addAll(Arrays.asList(classpath.split(File.pathSeparator)));
154 return result;
155 }
156
157 private List<String> resolveAotClasspath() throws DependencyResolutionException {
158 Stream<Artifact> aotArtifacts = Arrays.stream(AOT_MODULES)
159 .map(m -> new DefaultArtifact(MICRONAUT_AOT_GROUP_ID + ":" + MICRONAUT_AOT_ARTIFACT_ID_PREFIX + m + ":" + micronautAotVersion));
160 return toClasspath(dependencyResolutionService.artifactResultsFor(aotArtifacts, false));
161 }
162
163 private List<String> resolveAotPluginsClasspath() throws DependencyResolutionException {
164 if (aotDependencies != null && !aotDependencies.isEmpty()) {
165 Stream<Artifact> aotPlugins = aotDependencies.stream().map(d -> new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getType(), d.getVersion()));
166 return toClasspath(dependencyResolutionService.artifactResultsFor(aotPlugins, false));
167 } else {
168 return Collections.emptyList();
169 }
170 }
171
172 }