diff --git a/src/main/scala/sbtdocker/DockerCopy.scala b/src/main/scala/sbtdocker/DockerCopy.scala new file mode 100644 index 0000000..09599e8 --- /dev/null +++ b/src/main/scala/sbtdocker/DockerCopy.scala @@ -0,0 +1,54 @@ +package sbtdocker + +import sbt._ + +import scala.sys.process.{Process, ProcessLogger} +import scala.util.{Failure, Success, Try} + +object DockerCopy { + /** + * Copy Docker images to a docker machine. + * + * @param dockerMachinePath path to the docker machine binary + * @param imageNames names of the images to push + * @param log logger + */ + def apply(dockerPath: String, dockerMachinePath: String, dockerMachineName: String, imageNames: Seq[ImageName], log: Logger): Unit = { + imageNames.foreach { imageName => + apply(dockerPath, dockerMachinePath, dockerMachineName, imageName, log) + } + } + + /** + * Copy a Docker image to a docker machine. + * + * @param dockerMachinePath path to the docker machine binary + * @param imageName name of the image to push + * @param log logger + */ + def apply(dockerPath: String, dockerMachinePath: String, dockerMachineName: String, imageName: ImageName, log: Logger): Unit = { + log.info(s"Copying docker image with name: '$imageName' to machine '$dockerMachineName'") + + val processLog = ProcessLogger({ line => + log.info(line) + }, { line => + log.info(line) + }) + + def configCommand = dockerMachinePath :: "config" :: dockerMachineName :: Nil + + log.debug(s"Running command: '${configCommand.mkString(" ")}'") + + Try(Process(configCommand) lines_! processLog) match { + case Success(dockerMachineConfig) => + val saveCommand = dockerPath :: "save" :: imageName.toString :: Nil + val loadCommand = (dockerPath :: dockerMachineConfig.toList) :+ "load" + log.debug(s"Running command: '${saveCommand.mkString(" ")} | ${loadCommand.mkString(" ")}'") + val exitValue = Process(saveCommand) #| Process(loadCommand) ! processLog + if (exitValue != 0) sys.error("Failed to copy image") + case Failure(_) => + sys.error("Failed to get docker-machine config") + } + + } +} \ No newline at end of file diff --git a/src/main/scala/sbtdocker/DockerKeys.scala b/src/main/scala/sbtdocker/DockerKeys.scala index f9a87f5..eaef76d 100644 --- a/src/main/scala/sbtdocker/DockerKeys.scala +++ b/src/main/scala/sbtdocker/DockerKeys.scala @@ -4,8 +4,10 @@ import sbt._ object DockerKeys { val docker = taskKey[ImageId]("Build a Docker image.") - val dockerBuildAndPush = taskKey[ImageId]("Build a Docker image and pushes it to a registry.") - val dockerPush = taskKey[Unit]("Push a already built Docker image to a registry.") + val dockerBuildAndCopy = taskKey[ImageId]("Builds a Docker image and copies it to a docker machine.") + val dockerBuildAndPush = taskKey[ImageId]("Builds a Docker image and pushes it to a registry.") + val dockerPush = taskKey[Unit]("Push an already built Docker image to a registry.") + val dockerCopy = taskKey[Unit]("Copy an already built Docker image to a docker machine.") @deprecated("Use imageNames instead.", "1.0.0") val imageName = taskKey[ImageName]("Name of the built image.") @@ -13,5 +15,7 @@ object DockerKeys { val dockerfile = taskKey[DockerfileLike]("Definition of the Dockerfile that should be built.") val imageNames = taskKey[Seq[ImageName]]("Names of the built image.") val dockerPath = settingKey[String]("Path to the Docker binary.") + val dockerMachinePath = settingKey[String]("Path to the Docker Machine binary.") + val dockerMachineName = settingKey[String]("Name of docker machine to copy image to.") val buildOptions = settingKey[BuildOptions]("Options for the Docker build command.") } diff --git a/src/main/scala/sbtdocker/DockerPlugin.scala b/src/main/scala/sbtdocker/DockerPlugin.scala index fb16aff..892a4ab 100644 --- a/src/main/scala/sbtdocker/DockerPlugin.scala +++ b/src/main/scala/sbtdocker/DockerPlugin.scala @@ -9,6 +9,8 @@ object DockerPlugin extends AutoPlugin { val docker = DockerKeys.docker val dockerfile = DockerKeys.dockerfile val dockerPath = DockerKeys.dockerPath + val dockerMachineName = DockerKeys.dockerMachineName + val dockerMachinePath = DockerKeys.dockerMachinePath @deprecated("Use imageNames instead.", "1.0.0") val imageName = DockerKeys.imageName val imageNames = DockerKeys.imageNames diff --git a/src/main/scala/sbtdocker/DockerSettings.scala b/src/main/scala/sbtdocker/DockerSettings.scala index 3626c79..a17f28c 100644 --- a/src/main/scala/sbtdocker/DockerSettings.scala +++ b/src/main/scala/sbtdocker/DockerSettings.scala @@ -23,11 +23,25 @@ object DockerSettings { DockerPush(dockerPath, imageNames, log) }, + dockerCopy := { + val log = Keys.streams.value.log + val dockerPath = (DockerKeys.dockerPath in docker).value + val dockerMachinePath = (DockerKeys.dockerMachinePath in docker).value + val dockerMachineName = (DockerKeys.dockerMachineName in docker).value + val imageNames = (DockerKeys.imageNames in docker).value + + DockerCopy(dockerPath, dockerMachinePath, dockerMachineName, imageNames, log) + }, dockerBuildAndPush <<= (docker, dockerPush) { (build, push) => build.flatMap { id => push.map(_ => id) } }, + dockerBuildAndCopy <<= (docker, dockerCopy) { (build, copy) => + build.flatMap { id => + copy.map(_ => id) + } + }, dockerfile in docker := { sys.error( """A Dockerfile is not defined. Please define one with `dockerfile in docker` @@ -49,6 +63,8 @@ object DockerSettings { Seq((imageName in docker).value) }, dockerPath in docker := sys.env.get("DOCKER").filter(_.nonEmpty).getOrElse("docker"), + dockerMachineName in docker := "default", + dockerMachinePath in docker := sys.env.get("DOCKER_MACHINE").filter(_.nonEmpty).getOrElse("docker-machine"), buildOptions in docker := BuildOptions() )