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

Should employ mappings in ThisScope instead of mappings in Universal #746

Closed
frgomes opened this issue Feb 24, 2016 · 1 comment
Closed
Labels
documentation Documentation should be extended or updated

Comments

@frgomes
Copy link

frgomes commented Feb 24, 2016

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.

The basic idea consists on having multiple configurations for different packages to be generated. Each configuration tells which files will be present in the package. This is 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 the 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.
@muuki88
Copy link
Contributor

muuki88 commented Feb 24, 2016

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 */)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Documentation should be extended or updated
Projects
None yet
Development

No branches or pull requests

2 participants