Last active
November 4, 2016 18:19
-
-
Save rbellamy/63233cf847c177d63edd45f8b10c9210 to your computer and use it in GitHub Desktop.
Docker Helper Plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sbt.{Process, _} | |
import Keys._ | |
import com.typesafe.sbt.packager.docker.{DockerAlias, DockerPlugin} | |
import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport._ | |
import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport.stage | |
/* | |
* This helper plugin manipulates the behavior of the [[com.typesafe.sbt.packager.DockerPlugin]] in the following ways | |
* 1. Modifies the [[dockerAlias]] to NOT include the [[dockerRepository]] by default. This allows us to publish local | |
* docker images in the form of <package name>:<package version> - this makes them more easily launched from the local | |
* docker daemon. | |
* 2. This then means that the [[publish]] task must first tag the image to include the [[dockerRepository]] before doing | |
* the docker push. | |
* 3. Adds a [[docker:clean]] task that will delete all images associated with this project. | |
*/ | |
object DockerHelperPlugin extends AutoPlugin { | |
override def requires = DockerPlugin | |
override lazy val projectSettings = inConfig(Docker)(dockerSettings) | |
private def sudoCommand(useSudo: Boolean) = | |
if (useSudo) | |
Seq("sudo") | |
else | |
Seq() | |
def dockerSettings = Seq( | |
dockerUseSudo := false, | |
clean := cleanDockerTask.value, | |
publishLocal := publishLocalDocker.value, | |
tagDockerRepository := tagDocker.value, | |
publish <<= publish.dependsOn(tagDockerRepository) | |
) | |
lazy val dockerUseSudo = settingKey[Boolean]("Use sudo for docker commands") in Docker | |
lazy val clean = taskKey[Unit]("Clean docker images from local Docker daemon store.") in Docker | |
lazy val tagDockerRepository = taskKey[Unit]("Tag the current image with the repository.") in Docker | |
lazy val cleanDockerTask = Def.task { | |
val log: Logger = streams.value.log | |
log.info("Cleaning Docker images") | |
cleanDocker(dockerUseSudo.value, name.value, version.value, log) | |
} | |
/* | |
Alters the default behavior of the the DockerPlugin so that the publishLocal task leaves off the dockerRepository | |
value. | |
*/ | |
lazy val publishLocalDocker = Def.task { | |
val alias: DockerAlias = DockerAlias(None, None, name.value, Some(version.value)) | |
val buildOptions: Seq[String] = Seq("--force-rm") ++ Seq("-t", alias.versioned) ++ ( | |
if (dockerUpdateLatest.value) | |
Seq("-t", dockerAlias.value.latest) | |
else | |
Seq() | |
) | |
val buildCommands: Seq[String] = sudoCommand(dockerUseSudo.value) ++ Seq("docker", "build") ++ buildOptions ++ Seq(".") | |
DockerPlugin.publishLocalDocker(stage.value, buildCommands, streams.value.log) | |
} | |
/* | |
Alters the default behavior of the DockerPlugin so that the publish task first tags the local image with the | |
dockerRepository. Required since we altered the publishLocal task. | |
*/ | |
lazy val tagDocker = Def.task { | |
publishLocal.value | |
tagRepositoryDocker(dockerUseSudo.value, name.value, dockerRepository.value, (version in Docker).value, streams.value.log) | |
} | |
def cleanDocker(useSudo: Boolean, imageName: String, imageVersion: String, log: Logger): Unit = { | |
val listCommand = sudoCommand(useSudo) ++ Seq("docker", "images") | |
log.debug(s"Executing ${listCommand.mkString(" ")}") | |
val imageIds = (for { | |
i <- Process(listCommand).!!.split("\n"). | |
map(_.split("\\s{2,}")) if i(0).indexOf(imageName) > -1 && i(1) == imageVersion | |
} yield i(2)).distinct | |
log.debug(s"imageId: ${imageIds.mkString(" ")}") | |
if (!imageIds.isEmpty) { | |
val cleanCommand = sudoCommand(useSudo) ++ Seq("docker", "rmi", "-f") ++ imageIds | |
log.debug(s"Executing ${cleanCommand.mkString(" ")}") | |
val ret = Process(cleanCommand) ! logger(log) | |
if (ret != 0) | |
throw new RuntimeException("Nonzero exit value: " + ret) | |
} | |
} | |
def tagRepositoryDocker(useSudo: Boolean, name: String, repository: Option[String], version: String, log: Logger): Unit = { | |
for (repo <- repository) { | |
val tagCommand = sudoCommand(useSudo) ++ Seq("docker", "tag", s"$name:$version", s"$repo/$name:$version") | |
log.debug(s"Executing ${tagCommand.mkString(" ")}") | |
val ret = Process(tagCommand) ! logger(log) | |
if (ret != 0) | |
throw new RuntimeException("Nonzero exit value: " + ret) | |
} | |
} | |
def logger(log: Logger) = { | |
new ProcessLogger { | |
def error(err: => String) = { | |
err match { | |
case s if !s.trim.isEmpty => log.error(s) | |
case s => | |
} | |
} | |
def info(inf: => String) = inf match { | |
case s if !s.trim.isEmpty => log.info(s) | |
case s => | |
} | |
def buffer[T](f: => T) = f | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment