buildArg : buildImageCmdArguments.entrySet()) {
+ String key = buildArg.getKey();
+ String value = buildArg.getValue();
+ getLog().info("Using " + key + ": " + value);
+ buildImageCmd.withBuildArg(key, value);
+ }
- if (graalVmBuildArgs != null && !graalVmBuildArgs.isEmpty()) {
- getLog().info("Using GRAALVM_ARGS: " + graalVmBuildArgs);
- buildImageCmd = buildImageCmd.withBuildArg(GRAALVM_ARGS, graalVmBuildArgs);
+ dockerService.buildImage(buildImageCmd);
+ } else {
+ throw new IOException("Unable to convert native image build args to args file");
}
-
- dockerService.buildImage(buildImageCmd);
}
}
diff --git a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/DockerfileMojo.java b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/DockerfileMojo.java
index bbb70fd5a..c21b6da8f 100644
--- a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/DockerfileMojo.java
+++ b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/DockerfileMojo.java
@@ -20,19 +20,26 @@
import io.micronaut.maven.services.ApplicationConfigurationService;
import io.micronaut.maven.services.DockerService;
import io.micronaut.maven.jib.JibConfigurationService;
+import io.micronaut.maven.services.ExecutorService;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.invoker.MavenInvocationException;
import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static io.micronaut.maven.DockerNativeMojo.ARGS_FILE_PROPERTY_NAME;
/**
* Generates a Dockerfile
depending on the packaging
and micronaut.runtime
@@ -56,10 +63,13 @@ public class DockerfileMojo extends AbstractDockerMojo {
public static final String DOCKERFILE_NATIVE_STATIC = "DockerfileNativeStatic";
public static final String DOCKERFILE_NATIVE_ORACLE_CLOUD = "DockerfileNativeOracleCloud";
+ private final ExecutorService executorService;
+
@Inject
public DockerfileMojo(MavenProject mavenProject, DockerService dockerService, JibConfigurationService jibConfigurationService,
- ApplicationConfigurationService applicationConfigurationService) {
+ ApplicationConfigurationService applicationConfigurationService, ExecutorService executorService) {
super(mavenProject, jibConfigurationService, applicationConfigurationService, dockerService);
+ this.executorService = executorService;
}
@Override
@@ -77,7 +87,7 @@ public void execute() throws MojoExecutionException {
dockerfile.ifPresent(file -> getLog().info("Dockerfile written to: " + file.getAbsolutePath()));
- } catch (IOException e) {
+ } catch (IOException | MavenInvocationException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
@@ -129,7 +139,9 @@ private void processOracleFunctionDockerfile(File dockerfile) throws IOException
}
}
- private Optional buildDockerfileNative(MicronautRuntime runtime) throws IOException {
+ private Optional buildDockerfileNative(MicronautRuntime runtime) throws IOException, MavenInvocationException {
+ getLog().info("Generating GraalVM args file");
+ executorService.invokeGoal("org.graalvm.buildtools:native-maven-plugin", "write-args-file");
File dockerfile;
switch (runtime.getBuildStrategy()) {
case LAMBDA -> {
@@ -174,16 +186,10 @@ private void processDockerfile(File dockerfile) throws IOException {
result.add("");
}
} else if (line.contains("GRAALVM_") || line.contains("CLASS_NAME")) {
- String graalVmBuildArgs = getGraalVmBuildArgs();
- if (baseImageRun.contains("distroless") && !graalVmBuildArgs.contains(MOSTLY_STATIC_NATIVE_IMAGE_GRAALVM_FLAG)) {
- graalVmBuildArgs = MOSTLY_STATIC_NATIVE_IMAGE_GRAALVM_FLAG + " " + graalVmBuildArgs;
- }
-
result.add(line
.replace("${GRAALVM_VERSION}", graalVmVersion())
.replace("${GRAALVM_JVM_VERSION}", graalVmJvmVersion())
.replace("${GRAALVM_ARCH}", graalVmArch())
- .replace("${GRAALVM_ARGS}", graalVmBuildArgs)
.replace("${CLASS_NAME}", mainClass)
);
} else if (line.contains("PORT")) {
@@ -194,6 +200,26 @@ private void processDockerfile(File dockerfile) throws IOException {
}
}
+ String argsFile = mavenProject.getProperties().getProperty(ARGS_FILE_PROPERTY_NAME);
+ if (argsFile == null) {
+ Path targetPath = Paths.get(mavenProject.getBuild().getDirectory());
+ try (Stream listStream = Files.list(targetPath)) {
+ Path argsFilePath = listStream
+ .map(path -> path.getFileName().toString())
+ .filter(f -> f.startsWith("native-image") && f.endsWith("args"))
+ .map(targetPath::resolve)
+ .findFirst()
+ .orElse(null);
+ if (argsFilePath != null) {
+ argsFile = argsFilePath.toAbsolutePath().toString();
+ }
+ }
+ }
+ if (argsFile != null) {
+ List allNativeImageBuildArgs = MojoUtils.computeNativeImageArgs(nativeImageBuildArgs, baseImageRun, argsFile);
+ getLog().info("GraalVM native image build args: " + allNativeImageBuildArgs);
+ }
+
if (appArguments != null && !appArguments.isEmpty()) {
getLog().info("Using application arguments: " + appArguments);
result.add(getCmd());
diff --git a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/MojoUtils.java b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/MojoUtils.java
index 023ca4de0..935860bb6 100644
--- a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/MojoUtils.java
+++ b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/MojoUtils.java
@@ -21,6 +21,14 @@
import org.codehaus.plexus.util.Os;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import static io.micronaut.maven.AbstractDockerMojo.MOSTLY_STATIC_NATIVE_IMAGE_GRAALVM_FLAG;
/**
* Utility methods for different mojos.
@@ -49,4 +57,40 @@ public static String findJavaExecutable(ToolchainManager toolchainManager, Maven
}
return executable;
}
+
+ public static List computeNativeImageArgs(List nativeImageBuildArgs, String baseImageRun, String argsFile) throws IOException {
+ List allNativeImageBuildArgs = new ArrayList<>();
+ if (nativeImageBuildArgs != null && !nativeImageBuildArgs.isEmpty()) {
+ allNativeImageBuildArgs.addAll(nativeImageBuildArgs);
+ }
+ if (baseImageRun.contains("distroless") && !allNativeImageBuildArgs.contains(MOSTLY_STATIC_NATIVE_IMAGE_GRAALVM_FLAG)) {
+ allNativeImageBuildArgs.add(MOSTLY_STATIC_NATIVE_IMAGE_GRAALVM_FLAG);
+ }
+
+ Path argsFilePath = Paths.get(argsFile);
+ if (Files.exists(argsFilePath)) {
+ List args = Files.readAllLines(argsFilePath);
+ int cpPosition = args.indexOf("-cp");
+ args.remove(cpPosition);
+ args.remove(cpPosition);
+
+ List newArgs = args.stream()
+ .filter(arg -> !arg.startsWith("-H:Name"))
+ .filter(arg -> !arg.startsWith("-H:Class"))
+ .filter(arg -> !arg.startsWith("-H:Path"))
+ .filter(arg -> !arg.startsWith("-H:ConfigurationFileDirectories"))
+ .map(arg -> {
+ if (arg.startsWith("\\Q") && arg.endsWith("\\E")) {
+ return "\\Q/home/app/libs" + arg.substring(arg.lastIndexOf("/"));
+ } else {
+ return arg;
+ }
+ })
+ .toList();
+ allNativeImageBuildArgs.addAll(newArgs);
+ } else {
+ throw new IOException("Unable to find args file: " + argsFilePath);
+ }
+ return allNativeImageBuildArgs;
+ }
}
diff --git a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/CompilerService.java b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/CompilerService.java
index 748b65677..1f1740c47 100644
--- a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/CompilerService.java
+++ b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/CompilerService.java
@@ -19,8 +19,14 @@
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.logging.SystemStreamLog;
-import org.apache.maven.project.*;
-import org.apache.maven.shared.invoker.*;
+import org.apache.maven.project.DefaultDependencyResolutionRequest;
+import org.apache.maven.project.DependencyResolutionRequest;
+import org.apache.maven.project.DependencyResolutionResult;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectDependenciesResolver;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.MavenInvocationException;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
@@ -30,7 +36,11 @@
import javax.inject.Singleton;
import java.io.File;
import java.nio.file.Path;
-import java.util.*;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -68,14 +78,14 @@ public class CompilerService {
@SuppressWarnings("MnInjectionPoints")
@Inject
public CompilerService(MavenProject mavenProject, MavenSession mavenSession, ExecutorService executorService,
- ProjectDependenciesResolver resolver) {
+ ProjectDependenciesResolver resolver, Invoker invoker) {
this.resolver = resolver;
this.log = new SystemStreamLog();
this.mavenProject = mavenProject;
this.mavenSession = mavenSession;
this.executorService = executorService;
this.sourceDirectories = resolveSourceDirectories();
- this.invoker = new DefaultInvoker();
+ this.invoker = invoker;
}
/**
@@ -194,11 +204,6 @@ public String buildClasspath(List dependencies) {
* @return the invocation result.
*/
public InvocationResult packageProject() throws MavenInvocationException {
- InvocationRequest request = new DefaultInvocationRequest();
- request.setPomFile(mavenProject.getFile());
- request.setGoals(Collections.singletonList(MAVEN_JAR_PLUGIN + ":jar"));
- request.setBatchMode(true);
- request.setQuiet(true);
- return invoker.execute(request);
+ return executorService.invokeGoal(MAVEN_JAR_PLUGIN, "jar");
}
}
diff --git a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/ExecutorService.java b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/ExecutorService.java
index 58470a215..307043ac2 100644
--- a/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/ExecutorService.java
+++ b/micronaut-maven-plugin/src/main/java/io/micronaut/maven/services/ExecutorService.java
@@ -21,11 +21,17 @@
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.InvocationRequest;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.MavenInvocationException;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.twdata.maven.mojoexecutor.MojoExecutor;
import javax.inject.Inject;
import javax.inject.Singleton;
+import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
@@ -42,12 +48,17 @@ public class ExecutorService {
private final MojoExecutor.ExecutionEnvironment executionEnvironment;
private final MavenProject mavenProject;
+ private final MavenSession mavenSession;
+ private final Invoker invoker;
@SuppressWarnings("CdiInjectionPointsInspection")
@Inject
- public ExecutorService(MavenProject mavenProject, MavenSession mavenSession, BuildPluginManager pluginManager) {
+ public ExecutorService(MavenProject mavenProject, MavenSession mavenSession, BuildPluginManager pluginManager,
+ Invoker invoker) {
this.executionEnvironment = executionEnvironment(mavenProject, mavenSession, pluginManager);
this.mavenProject = mavenProject;
+ this.mavenSession = mavenSession;
+ this.invoker = invoker;
}
/**
@@ -99,4 +110,21 @@ public void executeGoal(String pluginGroup, String pluginArtifact, String plugin
final Plugin plugin = plugin(pluginGroup, pluginArtifact, pluginVersion);
executeMojo(plugin, goal(goal), configuration, executionEnvironment);
}
+
+ /**
+ * Executes a goal using the Maven shared invoker.
+ * @param pluginKey The plugin coordinates in the format groupId:artifactId
+ * @param goal The goal to execute
+ * @return The result of the invocation
+ * @throws MavenInvocationException If the goal execution fails
+ */
+ public InvocationResult invokeGoal(String pluginKey, String goal) throws MavenInvocationException {
+ InvocationRequest request = new DefaultInvocationRequest();
+ request.setPomFile(mavenProject.getFile());
+ request.setUserSettingsFile(mavenSession.getRequest().getUserSettingsFile());
+ request.setGoals(Collections.singletonList(pluginKey + ":" + goal));
+ request.setBatchMode(true);
+ request.setQuiet(true);
+ return invoker.execute(request);
+ }
}
diff --git a/micronaut-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/micronaut-maven-plugin/src/main/resources/META-INF/plexus/components.xml
index a9756425a..c151ce65c 100644
--- a/micronaut-maven-plugin/src/main/resources/META-INF/plexus/components.xml
+++ b/micronaut-maven-plugin/src/main/resources/META-INF/plexus/components.xml
@@ -161,6 +161,9 @@
default
+
+ org.graalvm.buildtools:native-maven-plugin:add-reachability-metadata
+
org.apache.maven.plugins:maven-resources-plugin:resources
@@ -169,7 +172,8 @@
${project.groupId}:${project.artifactId}:${project.version}:aot-analysis,
- ${project.groupId}:${project.artifactId}:${project.version}:graalvm-resources
+ ${project.groupId}:${project.artifactId}:${project.version}:graalvm-resources,
+ org.graalvm.buildtools:native-maven-plugin:write-args-file
${project.groupId}:${project.artifactId}:${project.version}:docker-native
diff --git a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileAwsCustomRuntime b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileAwsCustomRuntime
index 1d3ee72bf..2c6e72305 100644
--- a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileAwsCustomRuntime
+++ b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileAwsCustomRuntime
@@ -13,10 +13,10 @@ ENV PATH=/usr/lib/graalvm/bin:${PATH}
WORKDIR /home/app
COPY classes /home/app/classes
COPY dependency/* /home/app/libs/
-ARG GRAALVM_ARGS=""
+COPY *.args /home/app/graalvm-native-image.args
ARG CLASS_NAME
ENV USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false
-RUN native-image ${GRAALVM_ARGS} -H:Class=${CLASS_NAME} -H:Name=application --no-fallback -cp "/home/app/libs/*:/home/app/classes/"
+RUN native-image @/home/app/graalvm-native-image.args -H:Class=${CLASS_NAME} -H:Name=application -cp "/home/app/libs/*:/home/app/classes/"
FROM amazonlinux:latest
WORKDIR /function
diff --git a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNative b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNative
index 716d2c3dd..561ffba2c 100644
--- a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNative
+++ b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNative
@@ -5,13 +5,13 @@ WORKDIR /home/app
COPY classes /home/app/classes
COPY dependency/* /home/app/libs/
+COPY *.args /home/app/graalvm-native-image.args
ARG CLASS_NAME
-ARG GRAALVM_ARGS=""
ENV USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false
-RUN native-image ${GRAALVM_ARGS} -H:Class=${CLASS_NAME} -H:Name=application --no-fallback -cp "/home/app/libs/*:/home/app/classes/"
+RUN native-image @/home/app/graalvm-native-image.args -H:Class=${CLASS_NAME} -H:Name=application -cp "/home/app/libs/*:/home/app/classes/"
FROM ${BASE_IMAGE_RUN}
-ARG EXTRA_CMD
+ARG EXTRA_CMD=""
RUN if [[ -n "${EXTRA_CMD}" ]] ; then eval ${EXTRA_CMD} ; fi
COPY --from=builder /home/app/application /app/application
diff --git a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeDistroless b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeDistroless
index 06dde1837..deb3ff0cb 100644
--- a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeDistroless
+++ b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeDistroless
@@ -5,10 +5,10 @@ WORKDIR /home/app
COPY classes /home/app/classes
COPY dependency/* /home/app/libs/
+COPY *.args /home/app/graalvm-native-image.args
ARG CLASS_NAME
-ARG GRAALVM_ARGS=""
ENV USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false
-RUN native-image ${GRAALVM_ARGS} -H:Class=${CLASS_NAME} -H:Name=application --no-fallback -cp "/home/app/libs/*:/home/app/classes/"
+RUN native-image @/home/app/graalvm-native-image.args -H:Class=${CLASS_NAME} -H:Name=application -cp "/home/app/libs/*:/home/app/classes/"
FROM ${BASE_IMAGE_RUN}
COPY --from=builder /home/app/application /app/application
diff --git a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeOracleCloud b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeOracleCloud
index 2fff6a387..8c74d054b 100644
--- a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeOracleCloud
+++ b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeOracleCloud
@@ -5,9 +5,9 @@ WORKDIR /home/app
COPY classes /home/app/classes
COPY dependency/* /home/app/libs/
-ARG GRAALVM_ARGS=""
+COPY *.args /home/app/graalvm-native-image.args
ENV USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false
-RUN native-image ${GRAALVM_ARGS} --report-unsupported-elements-at-runtime -H:Class=com.fnproject.fn.runtime.EntryPoint -H:Name=application --no-fallback -cp "/home/app/libs/*:/home/app/classes/"
+RUN native-image @/home/app/graalvm-native-image.args --report-unsupported-elements-at-runtime -H:Class=com.fnproject.fn.runtime.EntryPoint -H:Name=application -cp "/home/app/libs/*:/home/app/classes/"
FROM fnproject/fn-java-fdk:jre17-latest AS fnfdk
diff --git a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeStatic b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeStatic
index 361d6cb2f..9833b1ec8 100644
--- a/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeStatic
+++ b/micronaut-maven-plugin/src/main/resources/dockerfiles/DockerfileNativeStatic
@@ -20,10 +20,10 @@ RUN curl -L -o zlib.tar.gz https://zlib.net/zlib-1.2.12.tar.gz && \
WORKDIR /home/app
COPY classes /home/app/classes
COPY dependency/* /home/app/libs/
+COPY *.args /home/app/graalvm-native-image.args
ARG CLASS_NAME
-ARG GRAALVM_ARGS=""
ENV USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false
-RUN native-image ${GRAALVM_ARGS} --static --libc=musl -H:Class=${CLASS_NAME} -H:Name=application --no-fallback -cp "/home/app/libs/*:/home/app/classes/"
+RUN native-image @/home/app/graalvm-native-image.args --static --libc=musl -H:Class=${CLASS_NAME} -H:Name=application -cp "/home/app/libs/*:/home/app/classes/"
FROM scratch
COPY --from=builder /home/app/application /app/application
diff --git a/pom.xml b/pom.xml
index 00151bc7e..c446833d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,7 +74,7 @@
17
3.9.0
4.0.0-SNAPSHOT
- 0.9.20
+ 0.9.21-SNAPSHOT
2.0.0-SNAPSHOT
2.0.0-SNAPSHOT
@@ -107,6 +107,17 @@
false
+
+ graalvm-native-build-tools-snapshots
+ GraalVM native-build-tools Snapshots
+ https://raw.githubusercontent.com/graalvm/native-build-tools/snapshots
+
+ true
+
+
+ false
+
+