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.github.dockerjava.api.command.BuildImageCmd; 019import com.google.cloud.tools.jib.plugins.common.PropertyNames; 020import io.micronaut.maven.core.DockerBuildStrategy; 021import io.micronaut.maven.core.MicronautRuntime; 022import io.micronaut.maven.jib.JibConfigurationService; 023import io.micronaut.maven.services.ApplicationConfigurationService; 024import io.micronaut.maven.services.DockerService; 025import io.micronaut.maven.services.ExecutorService; 026import org.apache.maven.execution.MavenSession; 027import org.apache.maven.plugin.MojoExecution; 028import org.apache.maven.plugin.MojoExecutionException; 029import org.apache.maven.plugins.annotations.Mojo; 030import org.apache.maven.plugins.annotations.ResolutionScope; 031import org.apache.maven.project.MavenProject; 032import org.apache.maven.shared.invoker.MavenInvocationException; 033 034import javax.inject.Inject; 035import java.io.File; 036import java.io.IOException; 037import java.nio.file.Files; 038import java.nio.file.LinkOption; 039import java.nio.file.StandardCopyOption; 040 041import static io.micronaut.maven.DockerfileMojo.DOCKERFILE_ORACLE_CLOUD; 042 043/** 044 * <p>Allows using a provided Dockerfile.</p> 045 * <p><strong>WARNING</strong>: this goal is not intended to be executed directly. Instead, specify the packaging type 046 * using the <code>packaging</code> property, eg:</p> 047 * 048 * <pre>mvn package -Dpackaging=docker</pre> 049 * 050 * @author Álvaro Sánchez-Mariscal 051 * @since 1.1 052 */ 053@Mojo(name = DockerMojo.DOCKER_PACKAGING, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) 054public class DockerMojo extends AbstractDockerMojo { 055 056 public static final String DOCKER_PACKAGING = "docker"; 057 058 private final ExecutorService executorService; 059 060 @SuppressWarnings("CdiInjectionPointsInspection") 061 @Inject 062 public DockerMojo(MavenProject mavenProject, JibConfigurationService jibConfigurationService, 063 ApplicationConfigurationService applicationConfigurationService, DockerService dockerService, 064 MavenSession mavenSession, MojoExecution mojoExecution, ExecutorService executorService) { 065 super(mavenProject, jibConfigurationService, applicationConfigurationService, dockerService, mavenSession, 066 mojoExecution); 067 this.executorService = executorService; 068 } 069 070 @Override 071 public void execute() throws MojoExecutionException { 072 var providedDockerfile = new File(mavenProject.getBasedir(), DockerfileMojo.DOCKERFILE); 073 if (shouldBuildWithDockerfile(providedDockerfile)) { 074 var dockerfile = determineDockerfile(providedDockerfile); 075 buildDockerfile(dockerfile, providedDockerfile.exists()); 076 } else { 077 if (jibConfigurationService.getFromImage().isEmpty()) { 078 System.setProperty(PropertyNames.FROM_IMAGE, getBaseImage()); 079 } 080 try { 081 String pluginGoalKey = "jib:" + jibBuildGoal; 082 getLog().info("Invoking " + pluginGoalKey); 083 var result = executorService.invokeGoal("com.google.cloud.tools:jib-maven-plugin", jibBuildGoal); 084 if (result.getExitCode() != 0) { 085 for (String line : result.outputHandler().getOutput()) { 086 getLog().error(line); 087 } 088 throw new MojoExecutionException("jib-maven-plugin failed, check logs above for details"); 089 } else { 090 for (String line : result.outputHandler().getOutput(pluginGoalKey)) { 091 getLog().info(line); 092 } 093 } 094 } catch (MavenInvocationException e) { 095 throw new MojoExecutionException("Could not build docker image", e); 096 } 097 } 098 } 099 100 private File determineDockerfile(File providedDockerfile) throws MojoExecutionException { 101 if (providedDockerfile.exists()) { 102 return providedDockerfile; 103 } 104 try { 105 return dockerService.loadDockerfileAsResource(DOCKERFILE_ORACLE_CLOUD); 106 } catch (IOException e) { 107 throw new MojoExecutionException("Error loading Dockerfile", e); 108 } 109 } 110 111 private boolean shouldBuildWithDockerfile(File providedDockerfile) { 112 var runtime = MicronautRuntime.valueOf(micronautRuntime.toUpperCase()); 113 return providedDockerfile.exists() || runtime.getBuildStrategy() == DockerBuildStrategy.ORACLE_FUNCTION; 114 } 115 116 private void buildDockerfile(File dockerfile, boolean providedDockerfileExists) throws MojoExecutionException { 117 try { 118 var runtime = MicronautRuntime.valueOf(micronautRuntime.toUpperCase()); 119 if (runtime.getBuildStrategy() == DockerBuildStrategy.ORACLE_FUNCTION && !providedDockerfileExists) { 120 oracleCloudFunctionCmd(dockerfile); 121 DockerfileMojo.processOracleFunctionDockerfile(dockerfile); 122 } 123 getLog().info("Using Dockerfile: " + dockerfile.getAbsolutePath()); 124 mavenProject.getProperties().put(PropertyNames.SKIP, "true"); 125 126 copyDependencies(); 127 128 String targetDir = mavenProject.getBuild().getDirectory(); 129 var targetDockerfile = new File(targetDir, dockerfile.getName()); 130 Files.copy(dockerfile.toPath(), targetDockerfile.toPath(), LinkOption.NOFOLLOW_LINKS, 131 StandardCopyOption.REPLACE_EXISTING); 132 133 BuildImageCmd buildImageCmd = dockerService.buildImageCmd() 134 .withDockerfile(targetDockerfile) 135 .withTags(getTags()) 136 .withBaseDirectory(new File(targetDir)); 137 getNetworkMode().ifPresent(buildImageCmd::withNetworkMode); 138 dockerService.buildImage(buildImageCmd); 139 } catch (IOException e) { 140 throw new MojoExecutionException(e.getMessage(), e); 141 } 142 } 143 144}