Search code examples
playframeworksbtdebsbt-native-packager

sbt-native-packager: How to create variants of a package e.g. with config extensions?


In a Play framework (2.3.x) Java project with sbt-native-packager (0.7.x), how can I create customer specific variants of .deb and .rpm packages?

Binary packages (.deb, .zip) are created with generic settings. Some customers require specialties like daemon user names or log locations according to their specifications. I would like to keep the generic packages and their settings as they are and add e.g. a new configuration with a few overrides so that I would get the variant with activator customer:packageBin.

What I have tried so far is to create a new SBT configuration which extends the Debian configuration of sbt-native-packager and thus to my limited understanding should inherit its settings and tasks. Then I’d like to be able to set e.g. daemonUser in Customer := "custom", but otherwise use the existing Debian settings.

My build.sbt for a sample Play-Java project (activator newplay-java):

import NativePackagerKeys._

name := """play-java"""

version := "1.0-SNAPSHOT"

lazy val Customer = config("customer") extend(Debian)

lazy val root = (project in file("."))
    .enablePlugins(PlayJava)
    .configs(Customer)
    .settings( inConfig(Customer)(packagerSettings) : _*)

scalaVersion := "2.11.1"

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  javaWs
)

maintainer := "Me"

packageSummary := "Example project"

packageDescription in Debian := "Longer description"

daemonUser in Customer := "custom-user"

As you can see I can now set e.g. daemonUser in Customer. In the Play console I can see that it is correctly applied with inspect customer:daemonUser. I can create a .deb package with activator customer:packageBin. But the package is almost empty and does not contain the application:

$ dpkg-deb -c target/play-java_1.0-SNAPSHOT_all.deb 
drwxr-xr-x root/root         0 2014-10-06 22:08 ./
drwxr-xr-x root/root         0 2014-10-06 22:08 ./usr/
drwxr-xr-x root/root         0 2014-10-06 22:08 ./usr/share/
drwxr-xr-x root/root         0 2014-10-06 22:08 ./usr/share/play-java/
drwxr-xr-x root/root         0 2014-10-06 22:08 ./universal/
drwxr-xr-x root/root         0 2014-10-06 22:08 ./universal/tmp/
drwxr-xr-x root/root         0 2014-10-06 22:08 ./universal/tmp/bin/
-rw-r--r-- root/root        64 2014-10-06 22:08 ./universal/tmp/bin/debianprerm
-rw-r--r-- root/root       137 2014-10-06 22:08 ./universal/tmp/bin/debianpostinst
lrwxrwxrwx root/root         0 2014-10-06 22:08 ./usr/share/play-java/logs -> /var/log/play-java

Are additional configurations per customer the way to go or does it not work the way I imagined?

Is there a different way to achive what I need, e.g. with sub-projects?


Solution

  • I’ve solved my problem with a different approach:

    The customer name has to be provided as system property. Inside build.sbt I have if-then-elses wherever a customer needs a special setting.

    build.sbt:

    val customer = sys.props.get("customer") getOrElse ""
    
    daemonUser in Linux := {
        customer match {
            case "customerA" => "custom-user"
            case _ => (daemonUser in Linux).value
        }
    }
    

    Then start the build with activator -Dcustomer=customerA debian:package-bin.

    Advantages:

    • Everything is in one build.sbt. The if-then-elses are easy to read and it is clear what is going on.
    • You can manipulate every aspect as needed, e.g. list of files to be packaged

    Disadvantages:

    • You have to run the build several times for each package variant you need.
    • The pacakge contents are not guaranteed to be identical e.g. if timestamps differ.

    I’m happy so far, but if someone comes along with a better idea I’d still like to hear it.