Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RMI command #123

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/scala/sbtdocker/DockerKeys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ object DockerKeys {
val docker = taskKey[ImageId]("Build a Docker image.")
val dockerBuildAndPush = taskKey[Map[ImageName, ImageDigest]]("Build a Docker image and pushes it to a registry.")
val dockerPush = taskKey[Map[ImageName, ImageDigest]]("Push a already built Docker image to a registry.")
val dockerRmi = taskKey[Map[ImageName, Seq[ImageDigest]]]("Delete built images.")

@deprecated("Use imageNames instead.", "1.0.0")
val imageName = taskKey[ImageName]("Name of the built image.")
Expand Down
61 changes: 61 additions & 0 deletions src/main/scala/sbtdocker/DockerRmi.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package sbtdocker

import sbt._

import scala.sys.process.{Process, ProcessLogger}

object DockerRmi {

/**
* Delete Docker images.
*
* @param dockerPath path to the docker binary
* @param imageNames names of the images to delete
* @param log logger
*/
def apply(dockerPath: String, imageNames: Seq[ImageName], log: Logger): Map[ImageName, Seq[ImageDigest]] = {
imageNames.map { imageName =>
apply(dockerPath, imageName, log)
}.toMap
}

/**
* Delete a Docker image.
*
* @param dockerPath path to the docker binary
* @param imageName name of the image to delete
* @param log logger
*/
def apply(dockerPath: String, imageName: ImageName, log: Logger): (ImageName, Seq[ImageDigest]) = {
log.info(s"Deleting docker image with name: '$imageName'")

var lines = Seq.empty[String]
val processLog = ProcessLogger(
{ line =>
log.info(line)
lines :+= line
},
{ line =>
log.info(line)
lines :+= line
}
)

val command = dockerPath :: "rmi" :: "-f" :: imageName.toString :: Nil
log.debug(s"Running command: '${command.mkString(" ")}'")

val process = Process(command)
val exitCode = process ! processLog
if (exitCode != 0) throw new DockerRmiException(s"Failed to run 'docker rmi' on image $imageName. Exit code $exitCode")

val DeletedImageDigestSha256 = ".*Deleted: ([^:]*):([0-9a-f]+).*".r

val deletedImages = lines.collect {
case DeletedImageDigestSha256(algo, digest) => ImageDigest(algo, digest)
}

(imageName, deletedImages)
}
}

class DockerRmiException(message: String) extends RuntimeException(message)
7 changes: 7 additions & 0 deletions src/main/scala/sbtdocker/DockerSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ object DockerSettings {

DockerPush(dockerPath, imageNames, log)
},
dockerRmi := {
val log = Keys.streams.value.log
val dockerPath = (docker / DockerKeys.dockerPath).value
val imageNames = (docker / DockerKeys.imageNames).value

DockerRmi(dockerPath, imageNames, log)
},
dockerBuildAndPush := Def.taskDyn {
docker.value
Def.task {
Expand Down
52 changes: 52 additions & 0 deletions src/sbt-test/sbt-docker/rmi/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
enablePlugins(DockerPlugin)

name := "scripted-rmi"

organization := "sbtdocker"

version := "0.1.0"

// Define a Dockerfile
docker / dockerfile := {
val jarFile = (Compile / packageBin / Keys.`package`).value
val classpath = (Compile / managedClasspath).value
val mainclass = (Compile / packageBin / mainClass).value.getOrElse {
sys.error("Expected exactly one main class")
}
val jarTarget = s"/app/${jarFile.getName}"
// Add all files on the classpath
val files = classpath.files.map(file => file -> s"/app/${file.getName}").toMap
// Make a colon separated classpath with the JAR file
val classpathString = files.values.mkString(":") + ":" + jarTarget
new Dockerfile {
from("openjdk:8-jre")
// Add all files that is on the classpath
files.foreach {
case (source, destination) =>
add(source, destination)
}
// Add the JAR and set the entry point
add(jarFile, jarTarget)
entryPoint("java", "-cp", classpathString, mainclass)
}
}

// Set a custom image name
docker / imageNames := {
val imageName = ImageName(
namespace = Some(organization.value),
repository = name.value,
tag = Some("v" + version.value))
Seq(imageName, imageName.copy(tag = Some("latest")))
}

val check = taskKey[Unit]("Check")

check := {
val names = (docker / imageNames).value
names.foreach { imageName =>
val process = scala.sys.process.Process("docker", Seq("run", "--rm", imageName.toString))
val out = process.!!
if (out.trim != "Hello World") sys.error("Unexpected output: " + out)
}
}
1 change: 1 addition & 0 deletions src/sbt-test/sbt-docker/rmi/project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.3.13
9 changes: 9 additions & 0 deletions src/sbt-test/sbt-docker/rmi/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
sys.props.get("plugin.version") match {
case Some(v) =>
addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % v)
case None =>
sys.error("The system property 'plugin.version' is not defined. " +
"Specify this property using the scriptedLaunchOpts -D.")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package simple

object HelloWorld extends App {
println("Hello World")
}
4 changes: 4 additions & 0 deletions src/sbt-test/sbt-docker/rmi/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
> docker
> check
> dockerRmi
-> check