View Javadoc
1   package io.micronaut.build;
2   
3   import com.google.common.io.FileWriteMode;
4   import io.micronaut.build.services.ApplicationConfigurationService;
5   import io.micronaut.build.services.DockerService;
6   import io.micronaut.build.services.JibConfigurationService;
7   import org.apache.maven.plugin.MojoExecutionException;
8   import org.apache.maven.plugins.annotations.Mojo;
9   import org.apache.maven.plugins.annotations.ResolutionScope;
10  import org.apache.maven.project.MavenProject;
11  
12  import javax.inject.Inject;
13  import java.io.File;
14  import java.io.IOException;
15  import java.nio.charset.Charset;
16  import java.nio.file.Files;
17  import java.util.ArrayList;
18  import java.util.List;
19  import java.util.Optional;
20  import java.util.stream.Collectors;
21  
22  import static io.micronaut.build.DockerNativeMojo.DOCKER_NATIVE_PACKAGING;
23  
24  /**
25   * <p>Generates a <code>Dockerfile</code> depending on the <code>packaging</code> and <code>micronaut.runtime</code>
26   * properties, eg:</p>
27   *
28   * <pre>mvn mn:dockerfile -Dpackaging=docker-native -Dmicronaut.runtime=lambda</pre>
29   *
30   * @author Álvaro Sánchez-Mariscal
31   * @since 1.1
32   */
33  @Mojo(name = "dockerfile", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
34  public class DockerfileMojo extends AbstractDockerMojo {
35  
36      public static final String DOCKER_PACKAGING = "docker";
37  
38      @Inject
39      public DockerfileMojo(MavenProject mavenProject, DockerService dockerService, JibConfigurationService jibConfigurationService,
40                            ApplicationConfigurationService applicationConfigurationService) {
41          super(mavenProject, jibConfigurationService, applicationConfigurationService, dockerService);
42      }
43  
44      @Override
45      public void execute() throws MojoExecutionException {
46          MicronautRuntime runtime = MicronautRuntime.valueOf(micronautRuntime.toUpperCase());
47          String packaging = mavenProject.getPackaging();
48          try {
49              copyDependencies();
50              Optional<File> dockerfile;
51  
52              switch (packaging) {
53                  case DOCKER_NATIVE_PACKAGING:
54                      dockerfile = buildDockerfileNative(runtime);
55                      break;
56  
57                  case DOCKER_PACKAGING:
58                      dockerfile = buildDockerfile(runtime);
59                      break;
60  
61                  default:
62                      throw new MojoExecutionException("Packaging is set to [" + packaging + "]. To generate a Dockerfile, set the packaging to either [" + DOCKER_PACKAGING + "] or [" + DOCKER_NATIVE_PACKAGING + "]");
63              }
64  
65              dockerfile.ifPresent(file -> getLog().info("Dockerfile written to: " + file.getAbsolutePath()));
66  
67          } catch (Exception e) {
68              throw new MojoExecutionException(e.getMessage(), e);
69          }
70      }
71  
72      private Optional<File> buildDockerfile(MicronautRuntime runtime) throws IOException {
73          File dockerfile = null;
74          switch (runtime.getBuildStrategy()) {
75              case ORACLE_FUNCTION:
76                  return Optional.ofNullable(dockerService.loadDockerfileAsResource("DockerfileOracleCloud"));
77  
78              case LAMBDA:
79              case DEFAULT:
80                  dockerfile = dockerService.loadDockerfileAsResource("Dockerfile");
81                  break;
82          }
83          processDockerfile(dockerfile);
84          return Optional.ofNullable(dockerfile);
85      }
86  
87      private Optional<File> buildDockerfileNative(MicronautRuntime runtime) throws IOException {
88          File dockerfile = null;
89          switch (runtime.getBuildStrategy()) {
90              case LAMBDA:
91                  dockerfile = dockerService.loadDockerfileAsResource("DockerfileAwsCustomRuntime");
92                  break;
93  
94              case ORACLE_FUNCTION:
95                  dockerfile = dockerService.loadDockerfileAsResource("DockerfileNativeOracleCloud");
96                  break;
97  
98              case DEFAULT:
99                  String dockerfileName = "DockerfileNative";
100                 if (staticNativeImage) {
101                     getLog().info("Generating a static native image");
102                     dockerfileName = "DockerfileNativeStatic";
103                 }
104                 dockerfile = dockerService.loadDockerfileAsResource(dockerfileName);
105                 break;
106         }
107         processDockerfile(dockerfile);
108         return Optional.ofNullable(dockerfile);
109 
110     }
111 
112     private void processDockerfile(File dockerfile) throws IOException {
113         if (dockerfile != null) {
114             List<String> allLines = Files.readAllLines(dockerfile.toPath());
115             List<String> result = new ArrayList<>();
116 
117             for (String line : allLines) {
118                 if (!line.startsWith("ARG")) {
119                     if (line.contains("BASE_IMAGE")) {
120                         result.add(line.replace("${BASE_IMAGE}", getFrom()));
121                     } else if (line.contains("GRAALVM_") || line.contains("CLASS_NAME")) {
122                         result.add(line
123                                 .replace("${GRAALVM_VERSION}", graalVmVersion())
124                                 .replace("${GRAALVM_JVM_VERSION}", graalVmJvmVersion())
125                                 .replace("${GRAALVM_ARGS} ", nativeImageBuildArgs != null ? nativeImageBuildArgs.trim() : "")
126                                 .replace("${CLASS_NAME}", mainClass)
127                         );
128                     } else if (line.contains("PORT")) {
129                         result.add(line.replace("${PORT}", getPort()));
130                     } else {
131                         result.add(line);
132                     }
133                 }
134             }
135 
136             if (appArguments != null && appArguments.size() > 0) {
137                 getLog().info("Using application arguments: " + appArguments);
138                 result.add(getCmd());
139             }
140 
141             Files.write(dockerfile.toPath(), result);
142         }
143     }
144 }