summaryrefslogtreecommitdiff
path: root/contrib/docker/src/DockerModule.scala
blob: bbf4d926d8f5bc7d91db5fe08089573efb3bb744 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import mill.T
import mill.scalalib.JavaModule
import os.Shellable.IterableShellable

import scala.collection.immutable._

trait DockerModule { outer: JavaModule =>

  trait DockerConfig extends mill.Module {
    /**
      * Tags that should be applied to the built image
      * In the standard registry/repository:tag format
      */
    def tags: T[Seq[String]] = T(List(outer.artifactName()))
    def labels: T[Map[String, String]] = Map.empty[String, String]
    def baseImage: T[String] = "gcr.io/distroless/java:latest"
    def pullBaseImage: T[Boolean] = T(baseImage().endsWith(":latest"))
    private def baseImageCacheBuster: T[(Boolean, Double)] = T.input {
      val pull = pullBaseImage()
      if(pull) (pull, Math.random()) else (pull, 0d)
    }

    def dockerfile: T[String] = T {
      val jarName = assembly().path.last
      val labelRhs = labels()
        .map { case (k, v) =>
          val lineBrokenValue = v
            .replace("\r\n", "\\\r\n")
            .replace("\n", "\\\n")
            .replace("\r", "\\\r")
          s""""$k"="$lineBrokenValue""""
        }
        .mkString(" ")

      val labelLine = if(labels().isEmpty) "" else s"LABEL $labelRhs"

      s"""
         |FROM ${baseImage()}
         |$labelLine
         |COPY $jarName /$jarName
         |ENTRYPOINT ["java", "-jar", "/$jarName"]
      """.stripMargin
    }

    final def build = T {
      val dest = T.ctx().dest

      val asmPath = outer.assembly().path
      os.copy(asmPath, dest / asmPath.last)

      os.write(dest / "Dockerfile", dockerfile())

      val log = T.ctx().log

      val tagArgs = tags().flatMap(t => List("-t", t))

      val (pull, _) = baseImageCacheBuster()
      val pullLatestBase = IterableShellable(if(pull) Some("--pull") else None)

      val result = os
        .proc("docker", "build", tagArgs, pullLatestBase, dest)
        .call(stdout = os.Inherit, stderr = os.Inherit)

      log.info(s"Docker build completed ${if(result.exitCode == 0) "successfully" else "unsuccessfully"} with ${result.exitCode}")
      tags()
    }

    final def push() = T.command {
      val tags = build()
      tags.foreach(t => os.proc("docker", "push", t).call(stdout = os.Inherit, stderr = os.Inherit))
    }
  }
}