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

WIP: Provide task to stage output in a format sufficient to build Docker images #236

Merged
merged 4 commits into from
May 14, 2014
Merged
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
5 changes: 4 additions & 1 deletion src/main/scala/com/typesafe/sbt/PackagerPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ object SbtNativePackager extends Plugin
with debian.DebianPlugin
with rpm.RpmPlugin
with windows.WindowsPlugin
with docker.DockerPlugin
with universal.UniversalPlugin
with GenericPackageSettings {

Expand All @@ -24,6 +25,7 @@ object SbtNativePackager extends Plugin
debianSettings ++
rpmSettings ++
windowsSettings ++
dockerSettings ++
universalSettings ++
Seq( // Bad defaults that let us at least not explode users who don't care about native packagers
NativePackagerKeys.maintainer := "",
Expand All @@ -35,6 +37,7 @@ object SbtNativePackager extends Plugin
def deploymentSettings = makeDeploymentSettings(Debian, packageBin in Debian, "deb") ++
makeDeploymentSettings(Rpm, packageBin in Rpm, "rpm") ++
makeDeploymentSettings(Windows, packageBin in Windows, "msi") ++
makeDeploymentSettings(Docker, packageBin in Docker, "tgz") ++
makeDeploymentSettings(Universal, packageBin in Universal, "zip") ++
addPackage(Universal, packageZipTarball in Universal, "tgz") ++
makeDeploymentSettings(UniversalDocs, packageBin in UniversalDocs, "zip") ++
Expand All @@ -50,4 +53,4 @@ object SbtNativePackager extends Plugin

// TODO - Add a few targets that detect the current OS and build a package for that OS.

}
}
3 changes: 2 additions & 1 deletion src/main/scala/com/typesafe/sbt/packager/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ object Keys extends linux.Keys
with debian.DebianKeys
with rpm.RpmKeys
with windows.WindowsKeys
with docker.DockerKeys
with universal.UniversalKeys {

// These keys are used by the JavaApp/JavaServer archetypes.
Expand All @@ -29,4 +30,4 @@ object Keys extends linux.Keys
val defaultLinuxInstallLocation = SettingKey[String]("defaultLinuxInstallLocation", "The location where we will install generic linux packages.")
val defaultLinuxLogsLocation = SettingKey[String]("defaultLinuxLogsLocation", "The location where application logs will be stored.")
val defaultLinuxConfigLocation = SettingKey[String]("defaultLinuxConfigLocation", "The location where application config files will be stored")
}
}
73 changes: 73 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.typesafe.sbt
package packager
package docker
import Keys._
import universal._
import sbt._

trait DockerPlugin extends Plugin with UniversalPlugin {
val Docker = config("docker") extend Universal

private[this] final def makeDockerContent(dockerBaseImage: String, dockerBaseDirectory: String, maintainer: String, daemonUser: String, name: String) = {
Dockerfile(
Cmd("FROM", dockerBaseImage),
Cmd("MAINTAINER", maintainer),
Cmd("ADD", "files /"),
Cmd("WORKDIR", "%s" format dockerBaseDirectory),
ExecCmd("RUN", "chown", "-R", daemonUser, "."),
Cmd("USER", daemonUser),
ExecCmd("ENTRYPOINT", "bin/%s" format name),
ExecCmd("CMD")
).makeContent
}

private[this] final def generateDockerConfig(
dockerBaseImage: String, dockerBaseDirectory: String, maintainer: String, daemonUser: String, normalizedName: String, target: File) = {
val dockerContent = makeDockerContent(dockerBaseImage, dockerBaseDirectory, maintainer, daemonUser, normalizedName)

val f = target / "Dockerfile"
IO.write(f, dockerContent)
f
}

def mapGenericFilesToDocker: Seq[Setting[_]] = {
def renameDests(from: Seq[(File, String)], dest: String) = {
for {
(f, path) <- from
newPath = "%s/%s" format (dest, path)
} yield (f, newPath)
}

inConfig(Docker)(Seq(
mappings <<= (mappings in Universal, defaultLinuxInstallLocation) map { (mappings, dest) =>
renameDests(mappings, dest)
}
))
}

def dockerSettings: Seq[Setting[_]] = Seq(
dockerBaseImage := "dockerfile/java",
sourceDirectory in Docker <<= sourceDirectory apply (_ / "docker"),
target in Docker <<= target apply (_ / "docker")
) ++ mapGenericFilesToDocker ++ inConfig(Docker)(Seq(
daemonUser := "daemon",
publishArtifact := false,
defaultLinuxInstallLocation := "/opt/docker",
dockerPackageMappings <<= (sourceDirectory) map { dir =>
MappingsHelper contentOf dir
},
mappings <++= dockerPackageMappings,
stage <<= (dockerGenerateConfig, dockerGenerateContext) map { (configFile, contextDir) => () },
dockerGenerateContext <<= (cacheDirectory, mappings, target) map {
(cacheDirectory, mappings, t) =>
val contextDir = t / "files"
stageFiles("docker")(cacheDirectory, contextDir, mappings)
contextDir
},
dockerGenerateConfig <<=
(dockerBaseImage, defaultLinuxInstallLocation, maintainer, daemonUser, normalizedName, target) map {
case (dockerBaseImage, baseDirectory, maintainer, daemonUser, normalizedName, target) =>
generateDockerConfig(dockerBaseImage, baseDirectory, maintainer, daemonUser, normalizedName, target)
}
))
}
26 changes: 26 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/docker/Keys.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.typesafe.sbt
package packager
package docker

import sbt._

trait DockerKeys {
val dockerGenerateConfig = TaskKey[File]("docker-generate-config", "Generates configuration file for Docker.")
val dockerGenerateContext = TaskKey[File]("docker-generate-context", "Generates context directory for Docker.")
val dockerPackageMappings = TaskKey[Seq[(File, String)]]("docker-package-mappings", "Generates location mappings for Docker build.")

val dockerBaseImage = SettingKey[String]("dockerBaseImage", "Base image for Dockerfile.")
}

object Keys extends DockerKeys {
def cacheDirectory = sbt.Keys.cacheDirectory
def mappings = sbt.Keys.mappings
def publishArtifact = sbt.Keys.publishArtifact
def sourceDirectory = sbt.Keys.sourceDirectory
def target = sbt.Keys.target
def defaultLinuxInstallLocation = packager.Keys.defaultLinuxInstallLocation
def normalizedName = universal.Keys.normalizedName
def stage = universal.Keys.stage
def daemonUser = linux.Keys.daemonUser
def maintainer = linux.Keys.maintainer
}
24 changes: 24 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.typesafe.sbt
package packager
package docker

trait CmdLike {
def makeContent: String
}

case class ExecCmd(cmd: String, args: String*) extends CmdLike {
def makeContent = "%s [%s]\n" format (cmd, args.map('"' + _ + '"').mkString(", "))
}

case class Cmd(cmd: String, arg: String) extends CmdLike {
def makeContent = "%s %s\n" format (cmd, arg)
}

/** Represents dockerfile used by docker when constructing packages. */
case class Dockerfile(commands: CmdLike*) {
def makeContent: String = {
val sb = new StringBuilder
commands foreach { sb append _.makeContent }
sb toString
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ trait UniversalPlugin extends Plugin {
dist
}

private[this] def stageFiles(config: String)(cacheDirectory: File, to: File, mappings: Seq[(File, String)]): Unit = {
def stageFiles(config: String)(cacheDirectory: File, to: File, mappings: Seq[(File, String)]): Unit = {
val cache = cacheDirectory / ("packager-mappings-" + config)
val copies = mappings map {
case (file, path) => file -> (to / path)
Expand Down
7 changes: 7 additions & 0 deletions src/sbt-test/docker/staging/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import NativePackagerKeys._

packagerSettings

name := "simple-test"

version := "0.1.0"
1 change: 1 addition & 0 deletions src/sbt-test/docker/staging/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version"))
1 change: 1 addition & 0 deletions src/sbt-test/docker/staging/src/universal/conf/test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Test configuration to include in zips.
4 changes: 4 additions & 0 deletions src/sbt-test/docker/staging/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Stage the distribution and ensure files show up.
> show docker:stage
$ exists target/docker/Dockerfile
$ exists target/docker/files