How do I create a tarball and a zip for a single m

2019-08-15 03:12发布

问题:

I have a multi-project build with a particularly messy module which contain several mainClasses. I would like to create several distribution packages for this messy module, each distribution package employing distinct file sets and employing different formats. Ideas?

回答1:

This is the answer from the sbt-nativer-packager issue tracker where the same question was posted.

I'm adding this from the gitter chat as well:

I'm just arriving in this chat room and my knowledge of sbt-native-packager is virtually zero... but anyway... looks to me that JavaAppPackaging and other archetypes should actually be configurations extended from Universal. In this scenario, I would just create my own configuration extended from JavaAppPackaging and tweak the necessary bits according to my needs. And, finally, if the plugin just picks mappings in ThisScope... it would pick my own scope, and not JavaAppPackaging... and not Universal. So, let's go through this one by one.

The sbt-native-packager plugin always pick mappings in Universal. This is not ideal. It should conceptually pick mappings in ThisScope SBT native packager provides two categories of AutoPlugins: FormatPlugins and ArchetypePlugins. FormatPlugins provide a new package format, e.g. UniversalPlugin (zip, tarball) or DebianPlugins (.deb). These plugins form a a hierarchy as they are build on top of each other:

          SbtNativePackager
                +
                |
                |
  +-------+  Universal  +--------+
  |                              |
  |             +                |
  |             |                |
  +             +                +
Docker    +-+ Linux +-+      Windows
          |           |
          |           |
          +           +
       Debian        RPM

mappings, which define a file -> targetpath relation, are inherited with this pattern

mappings in ParentFormatPluginScope := (mappings in FormatPluginScope).value

So for docker it looks like this

mappings in Docker := (mappings in Universal).value

The linux format plugins use specialized mappings to preserve file permissions, but are basically the same.

Since sbt-native-packager plugin always pick mappings in Universal, I have to redefine mappings in Universal in each of my configurations Yes. If you want to define your own scope and inherit the mappings and change them you have to do this, like all other packaging plugins, too. I recommend putting this code into custom AutoPlugins in your project folder.

For example (not tested, imports may be missing )

import sbt._

object BuilderRSPlugin extends AutoPlugin {
   def requires = JavaAppPackaging

   object autoImport {
        val BuilderRS = config("builderrs") extend Universal
   }

  import autoImport._

  override lazy val projectSettings = Seq(
     mappings in BuilderRS := (mappings in Universal).value
  )
}

looks to me that JavaAppPackaging and other archetypes should actually be configurations extended from Universal JavaAppPackaging is an archetype, which means this plugin doesn't bring any new packaging formats, thus no new scopes. It configures all the packaging formats it can and enables them.

You package stuff by specifying the scope:

universal:packageBin
debian:packageBin
windows:packageBin

So if you need to customize your output format you are doing this in the respecting scope.

mappings in Docker := (mappings in Docker).value.filter( /* what ever you want to filter */)


回答2:

See: https://github.com/sbt/sbt-native-packager/issues/746

IMPORTANT: This is an "answer in progress". IT DOES NOT WORK YET!

This is an example of how one could achieve this.

The basic idea is that we add configurations for different packages to be generated. Each configuration tells which files will be present in the package. This does not work as expected. See my comments after the code.

lazy val BuilderRS = sbt.config("BuilderRS").extend(Compile,Universal)
lazy val BuilderRV = sbt.config("BuilderRV").extend(Compile,Universal)

addCommandAlias("buildRS", "MessyModule/BuilderRS:packageZipTarball")
addCommandAlias("buildRV", "MessyModule/BuilderRV:packageBin") // ideally should be named packageZip

lazy val Star5FunctionalTestSupport =
  project
    .in(file("MessyModule"))
    .enablePlugins(JavaAppPackaging)
    .settings((buildSettings): _*)

    .configs(Universal,BuilderRS,BuilderRV)

    .settings(inConfig(BuilderRS)(
      Defaults.configSettings ++ JavaAppPackaging.projectSettings ++
        Seq(
          executableScriptName := "rs",
          mappings in Universal :=
            (mappings in Universal).value
              .filter {
                case (file, name) =>  ! file.getAbsolutePath.endsWith("/bin/rv")
              },
          topLevelDirectory in Universal :=
            Some(
              "ftreports-" +
                new java.text.SimpleDateFormat("yyyyMMdd_HHmmss")
                  .format(new java.util.Date())),
          mainClass in ThisScope := Option(mainClassRS))): _*)

    //TODO: SEE COMMENTS BELOW ===============================================
    // .settings(inConfig(BuilderRV)(
    //   Defaults.configSettings ++ JavaAppPackaging.projectSettings ++
    //     Seq(
    //       packageBin <<= packageBin in Universal,
    //       executableScriptName := "rv",
    //       mappings in ThisScope :=
    //         (mappings in Universal).value
    //           .filter {
    //             case (file, name) =>  ! file.getAbsolutePath.endsWith("/bin/rs")
    //           },
    //       topLevelDirectory in Universal :=
    //         Some(
    //           "ftviewer-" +
    //             new java.text.SimpleDateFormat("yyyyMMdd_HHmmss")
    //               .format(new java.util.Date())),
    //       mainClass in ThisScope := Option(mainClassRV))): _*)

Now observe configuration BuilderRV which in comments.

It is basically the same thing as configuration BuilderRS, except that we are now deploying a different shell script in the bin folder. There some other small differences, but not relevant to this argumentation. There are two problems:

  1. The sbt-native-packager plugin always pick mappings in Universal. This is not ideal. It should conceptually pick mappings in ThisScope.

  2. Since sbt-native-packager plugin always pick mappings in Universal, I have to redefine mappings in Universal in each of my configurations. And this is a problem because mappings in Universal is defined as a function of itself in all configurations: the result is that we ended up chaining logic to mapppings in Universal each time we redefined it in each configuration. This causes trouble in this example in particular because the configuration BuilderRV (the second one) will perform not only its filter, but also the filter defined in BuilderRS (the first one), which is not what I want.