Search code examples
scalasbtrpmsbt-native-packager

Building paths in SBT for the packageMappings of the sbt-native-packager


I am very new to SBT and need to create a RPM package for one of my project. The RPM contains only 1 file, which is a one-jar created by the sbt-onejar plugin). I want to use sbt-native-packager plugin and have created a Packagin.scala file under the /project directory like this:

object Packaging {
  val settings: Seq[Setting[_]] = packagerSettings ++ deploymentSettings ++ mapGenericFilesToLinux ++ Seq(

    maintainer := "Team",
    packageSummary := "Summary",
    packageDescription := """Description""",

    mappings in Universal += {
      file("target/scala-2.10/projectname_2.10-0.1-one-jar.jar") -> "/opt/projectname/projectname-0.1.jar"
    },

    linuxPackageMappings in Rpm <+= (baseDirectory) map { _:File =>
      (packageMapping(file("target/scala-2.10/projectname_2.10-0.1-one-jar.jar") -> "/opt/projectname/projectname-0.1.jar")
        withUser "someusr" withGroup "somegroup" withPerms "0755")
    },

    name in Rpm := "projectname",
    version in Rpm <<= version apply { sv => sv split "[^\\d]" filterNot (_.isEmpty) mkString "." },
    rpmRelease := "1",
    rpmVendor := "Vendor",
    rpmUrl := Some("url"),
    rpmGroup := Some("group"),
    rpmLicense := Some("BSD")
  )
}

1) I don't want to hardcode the file names. Instead of having "target/scala-2.10/projectname_2.10-0.1-one-jar.jar" I need a way to use existing SettingKey's, i.e. target + "scala-" + scalaVersion + "/" + name + "_" + scalaVersion + "-" + version + "-one-jar.jar" - how do you do this=

2) For the value rpmRelease := "1" I want to use a System property, i.e. in Maven I would do ${rpm.buildNumber}, how does that work in SBT?

3) Is there anything I should do better in regards to the sbt-native-packager plugin?


Solution

  • 1) You should always use task output in sbt rather than raw filesystem lookups. Because sbt has parallel execution, if you don't put an explicit dependency on the output of a task, then you have no guarantee that a file will be created before you run your task.

    In that vein you want to change your package mappings line to be something like this:

    mappings in Universal += {
      oneJar.value -> "/opt/projectname/projectname-0.1.jar"
    },
    

    Where the oneJar key is defined in the onejar plugin.

    2) Sbt just uses scala for the build language, so you can grab system properties similarly (but please also provide a default):

    rpmRelease := Option(sys.props("rpm.buildNumber")) getOrElse "1"
    

    3) Right now you're defining a generic package and redefining the same file in the Rpm with a different user. The mapGenericFilesToLinux settings still lack a few customizations, but if you're not creating universal distributions, you should be able to drop that bit of settings and instead directly configure your linux package:

    linuxPackageMappings in Rpm <+= (oneJar) map { jar:File =>
      (packageMapping(jar -> "/opt/projectname/projectname-0.1.jar")
        withUser "someusr" withGroup "somegroup" withPerms "0755")
    },