Skip to content

Commit

Permalink
Replace dockerVersion with dockerApiVersion (#1296)
Browse files Browse the repository at this point in the history
* Add dockerApiVersion validation

* Fix typo

* Move `dockerApiVersion` to `DockerKeysEx`

* Restore previous methods as deprecated for compatibility issues

* Update docs

* Set `sbtApiVersion` for integration test
  • Loading branch information
rodrigorn authored and muuki88 committed Jan 18, 2020
1 parent ef57f57 commit 48fbde3
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.typesafe.sbt.packager.docker

import scala.util.matching.Regex

case class DockerApiVersion(major: Int, minor: Int)

object DockerApiVersion {
private val DockerApiVersionPattern: Regex = """^'?([0-9]+)\.([0-9]+)'?$""".r

def parse(version: String): Option[DockerApiVersion] =
Option(version).collect {
case DockerApiVersionPattern(major, minor) => new DockerApiVersion(major.toInt, minor.toInt)
}
}
42 changes: 24 additions & 18 deletions src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ object DockerPlugin extends AutoPlugin {
dockerVersion := Try(Process(dockerExecCommand.value ++ Seq("version", "--format", "'{{.Server.Version}}'")).!!).toOption
.map(_.trim)
.flatMap(DockerVersion.parse),
dockerApiVersion := Try(
Process(dockerExecCommand.value ++ Seq("version", "--format", "'{{.Server.APIVersion}}'")).!!
).toOption
.map(_.trim)
.flatMap(DockerApiVersion.parse),
dockerBuildOptions := Seq("--force-rm") ++ dockerAliases.value.flatMap { alias =>
Seq("-t", alias.toString)
},
Expand Down Expand Up @@ -243,8 +248,8 @@ object DockerPlugin extends AutoPlugin {
nonEmptyMappings((mappings in Docker).value),
filesExist((mappings in Docker).value),
validateExposedPorts(dockerExposedPorts.value, dockerExposedUdpPorts.value),
validateDockerVersion(dockerVersion.value),
validateDockerPermissionStrategy(dockerPermissionStrategy.value, dockerVersion.value)
validateDockerVersion(dockerApiVersion.value),
validateDockerPermissionStrategy(dockerPermissionStrategy.value, dockerVersion.value, dockerApiVersion.value)
),
dockerPackageMappings := MappingsHelper.contentOf(sourceDirectory.value),
dockerGenerateConfig := {
Expand Down Expand Up @@ -638,8 +643,8 @@ object DockerPlugin extends AutoPlugin {
}
}

private[this] def validateDockerVersion(dockerVersion: Option[DockerVersion]): Validation.Validator = () => {
dockerVersion match {
private[this] def validateDockerVersion(dockerApiVersion: Option[DockerApiVersion]): Validation.Validator = () => {
dockerApiVersion match {
case Some(_) => List.empty
case None =>
List(
Expand All @@ -649,7 +654,7 @@ object DockerPlugin extends AutoPlugin {
howToFix = """|sbt-native packager tries to parse the `docker version` output. This can fail if
|
| - the output has changed:
| $ docker version --format '{{.Server.Version}}'
| $ docker version --format '{{.Server.APIVersion}}'
|
| - no `docker` executable is available
| $ which docker
Expand All @@ -658,52 +663,53 @@ object DockerPlugin extends AutoPlugin {
|
|You can display the parsed docker version in the sbt console with:
|
| sbt:your-project> show dockerVersion
| sbt:your-project> show dockerApiVersion
|
|As a last resort you could hard code the docker version, but it's not recommended!!
|
| import com.typesafe.sbt.packager.docker.DockerVersion
| dockerVersion := Some(DockerVersion(18, 9, 0, Some("ce"))
| import com.typesafe.sbt.packager.docker.DockerApiVersion
| dockerApiVersion := Some(DockerApiVersion(1, 40))
""".stripMargin
)
)
}
}

private[this] def validateDockerPermissionStrategy(strategy: DockerPermissionStrategy,
dockerVersion: Option[DockerVersion]): Validation.Validator =
dockerVersion: Option[DockerVersion],
dockerApiVersion: Option[DockerApiVersion]): Validation.Validator =
() => {
(strategy, dockerVersion) match {
case (DockerPermissionStrategy.MultiStage, Some(ver)) if !DockerSupport.multiStage(ver) =>
(strategy, dockerVersion, dockerApiVersion) match {
case (DockerPermissionStrategy.MultiStage, Some(ver), Some(apiVer)) if !DockerSupport.multiStage(ver, apiVer) =>
List(
ValidationError(
description =
s"The detected Docker version $ver is not compatible with DockerPermissionStrategy.MultiStage",
howToFix =
"""|sbt-native packager tries to parse the `docker version` output.
|To use multi-stage build, upgrade your Docker, pick another strategy, or override dockerVersion:
|To use multi-stage build, upgrade your Docker, pick another strategy, or override dockerApiVersion:
|
| import com.typesafe.sbt.packager.docker.DockerPermissionStrategy
| dockerPermissionStrategy := DockerPermissionStrategy.Run
|
| import com.typesafe.sbt.packager.docker.DockerVersion
| dockerVersion := Some(DockerVersion(18, 9, 0, Some("ce"))
| import com.typesafe.sbt.packager.docker.DockerApiVersion
| dockerApiVersion := Some(DockerApiVersion(1, 40))
""".stripMargin
)
)
case (DockerPermissionStrategy.CopyChown, Some(ver)) if !DockerSupport.chownFlag(ver) =>
case (DockerPermissionStrategy.CopyChown, Some(ver), Some(apiVer)) if !DockerSupport.chownFlag(ver, apiVer) =>
List(
ValidationError(
description =
s"The detected Docker version $ver is not compatible with DockerPermissionStrategy.CopyChown",
howToFix = """|sbt-native packager tries to parse the `docker version` output.
|To use --chown flag, upgrade your Docker, pick another strategy, or override dockerVersion:
|To use --chown flag, upgrade your Docker, pick another strategy, or override dockerApiVersion:
|
| import com.typesafe.sbt.packager.docker.DockerPermissionStrategy
| dockerPermissionStrategy := DockerPermissionStrategy.Run
|
| import com.typesafe.sbt.packager.docker.DockerVersion
| dockerVersion := Some(DockerVersion(18, 9, 0, Some("ce"))
| import com.typesafe.sbt.packager.docker.DockerApiVersion
| dockerApiVersion := Some(DockerApiVersion(1, 40))
""".stripMargin
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ object DockerSpotifyClientPlugin extends AutoPlugin {

override lazy val projectSettings: Seq[Setting[_]] = inConfig(Docker)(clientSettings)

def clientSettings = Seq(publishLocal := publishLocalDocker.value, dockerVersion := dockerServerVersion.value)
def clientSettings =
Seq(
publishLocal := publishLocalDocker.value,
dockerVersion := dockerServerVersion.value,
dockerApiVersion := dockerServerApiVersion.value
)

def publishLocalDocker: Def.Initialize[Task[Unit]] = Def.task {
val context = stage.value
Expand All @@ -71,6 +76,11 @@ object DockerSpotifyClientPlugin extends AutoPlugin {
docker.dockerServerVersion()
}

def dockerServerApiVersion: Def.Initialize[Task[Option[DockerApiVersion]]] = Def.task {
val docker = new DockerClientTask()
docker.dockerServerApiVersion()
}

}

/**
Expand Down Expand Up @@ -111,4 +121,9 @@ private class DockerClientTask {
val docker: DockerClient = DefaultDockerClient.fromEnv().build()
DockerVersion.parse(docker.version().version())
}

def dockerServerApiVersion(): Option[DockerApiVersion] = {
val docker: DockerClient = DefaultDockerClient.fromEnv().build()
DockerApiVersion.parse(docker.version().apiVersion())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@ package com.typesafe.sbt.packager.docker

object DockerSupport {

@deprecated
def chownFlag(version: DockerVersion): Boolean =
(version.major == 17 && version.minor >= 9) || version.major > 17

@deprecated
def multiStage(version: DockerVersion): Boolean =
(version.major == 17 && version.minor >= 5) || version.major > 17

def chownFlag(version: DockerVersion, apiVersion: DockerApiVersion): Boolean =
((version.major == 17 && version.minor >= 9) || version.major > 17) || (apiVersion.major == 1 && apiVersion.minor >= 32)

def multiStage(version: DockerVersion, apiVersion: DockerApiVersion): Boolean =
((version.major == 17 && version.minor >= 5) || version.major > 17) || (apiVersion.major == 1 && apiVersion.minor >= 29)
}
1 change: 1 addition & 0 deletions src/main/scala/com/typesafe/sbt/packager/docker/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ private[packager] trait DockerKeysEx extends DockerKeys {
lazy val dockerChmodType = settingKey[DockerChmodType]("The file permissions for the files copied into Docker image.")
lazy val dockerAdditionalPermissions =
taskKey[Seq[(DockerChmodType, String)]]("Explicit chmod calls to some of the paths.")
val dockerApiVersion = TaskKey[Option[DockerApiVersion]]("dockerApiVersion", "The docker server api version")
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import com.typesafe.sbt.packager.docker._

dockerVersion := Some(DockerVersion(1, 13, 0, None))
dockerApiVersion := Some(DockerApiVersion(1, 28))
3 changes: 3 additions & 0 deletions src/sphinx/formats/docker.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ Environment Settings
``dockerVersion``
The docker server version. Used to leverage new docker features while maintaining backwards compatibility.

``dockerApiVersion``
The docker server API version. Used to leverage new docker features while maintaining backwards compatibility.

Publishing Settings
~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.typesafe.sbt.packager.docker

import org.scalatest._

class DockerApiVersionSpec extends FlatSpec with DiagrammedAssertions {
"DockerApiVersion" should "parse 1.40" in {
val v = DockerApiVersion.parse("1.40")
assert(v == Some(DockerApiVersion(1, 40)))
}
}

0 comments on commit 48fbde3

Please sign in to comment.