如何支持在库中的多个版本的Scala(How to support multiple Scala v

2019-08-04 02:21发布

I have a fairly normal Scala project currently being built using Maven. I would like to support both Scala 2.9.x and the forthcoming 2.10, which is not binary or source compatible. I am willing to entertain converting to SBT if necessary, but I have run into some challenges.

My requirements for this project are:

  • Single source tree (no branching). I believe that trying to support multiple concurrent "master" branches for each Scala version will be the quickest way to miss bugfixes between the branches.

  • Version specific source directories. Since the Scala versions are not source compatibile, I need to be able to specify an auxiliary source directory for version specific sources.

  • Version specific source jars. End users should be able to download the correct source jar, with the correct version specific sources, for their version of Scala for IDE integration.

  • Integrated deployment. I currently use the Maven release plugin to deploy new versions to the Sonatype OSS repository, and would like to have a similarly simple workflow for releases.

  • End-user Maven support. My end users are often Maven users, and so a functional POM that accurately reflects dependencies is critical.

  • Shaded jar support. I need to be able to produce a JAR that includes a subset of my dependenices and removes the shaded dependencies from the published POM.

Things I have tried:

  • Maven profiles. I created a set of Maven profiles to control what version of Scala is used to build, using the Maven build-helper plugin to select the version specific source tree. This was working well until it came time to publish;

    • Using classifiers to qualify versions doesn't work well, because the source jars would also need custom classifiers ('source-2.9.2', etc.), and most IDE tools wouldn't know how to locate them.

    • I tried using a Maven property to add the SBT-style _${scala.version} suffix to the artifact name, but Maven does not like properties in the artifact name.

  • SBT. This works well once you can grok it (no small task despite extensive documentation). The downside is that there does not seem to be an equivalent to the Maven shade plugin. I've looked at:

    • Proguard. The plugin is not updated for SBT 0.12.x, and won't build from source because it depends on another SBT plugin that has changed groupIds, and doesn't have a 0.12.x version under the old name. I have not yet been able to work out how to instruct SBT to ignore/replace the plugin dependency.

    • OneJar. This uses custom class loading to run Main classes out of embedded jars, which is not the desired result; I want the class files of my project to be in the jar along with (possibly renamed) class files from my shaded dependencies.

    • SBT Assembly plugin. This can work to a degree, but the POM file appears to include the dependencies that I'm trying to shade, which doesn't help my end users.

I accept that there may not be a solution that does what I want for Scala, and/or I may need to write my own Maven or Scala plugins to accomplish the goal. But if I can I'd like to find an existing solution.

Update

I am close to accepting @Jon-Ander's excellent answer, but there is still one outstanding piece for me, which is a unified release process. The current state of my build.sbt is on GitHub. (I'll reproduce it here in an answer later for posterity).

The sbt-release plugin does not support multi-version builds (i.e., + release does not behave as one might like), which makes a sort of sense as the process of release tagging doesn't really need to happen across versions. But I would like two parts of the process to be multi-version: testing and publishing.

What I'd like to have happen is something akin to two-stage maven-release-plugin process. The first stage would do the administrative work of updating Git and running the tests, which in this case would mean running + test so that all versions are tested, tagging, updating to snapshot, and then pushing the result to upstream.

The second stage would checkout the tagged version and + publish, which will rerun the tests and push the tagged versions up to the Sonatype repository.

我怀疑,我可以写releaseProcess值是每一个做这些,但我不知道我是否能够支持多releaseProcess在我的价值观build.sbt 。 它也许可以用一些额外的工作范围,但SBT的那部分仍然是陌生majick给我。

我现在所做的是改变了releaseProcess不公布。 然后,我有手签出标记的形式和运行+ publish的事实,这是接近我想要什么,但不妥协,特别是因为测试仅在释放过程中的当前斯卡拉版本上运行之后。 我可以用一个过程,不是两阶段像Maven插件活着,但确实实现多版本测试和发布。

其他任何意见,可以让我在整个最后一英里,将不胜感激。

Answer 1:

这其中大部分在SBT很好支持的单一源代码树中

版本特定的源目录通常不需要。 Scala程序往往是源兼容的-所以常常在事实crossbuilding( http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build )在SBT一流的支持。

如果你真的需要特定版本的代码,你可以添加额外的源文件夹。 在build.sbt文件把这将增加“的src / main / scala- [scalaVersion]”为每个你除了常规“的src / main /斯卡拉” crossbuild版本源目录。 (没有也可用于生成版本之间的垫片插件,但我还没有尝试过- https://github.com/sbt/sbt-scalashim )

unmanagedSourceDirectories in Compile <+= (sourceDirectory in Compile, scalaVersion){ (s,v) => s / ("scala-"+v) }

特定版本的源罐子 - 见crossbuilding,开箱的

综合部署- https://github.com/sbt/sbt-release (有真棒git的整合也是如此)

Maven的最终用户- http://www.scala-sbt.org/release/docs/Detailed-Topics/Publishing.html

阴影-我已经使用这个https://github.com/sbt/sbt-assembly已经对我的需要的罚款。 您与组装插件问题可以通过改写产生的POM来解决。 下面是一个例子剥开乔达时间。

pomPostProcess := {
    import xml.transform._
    new RuleTransformer(new RewriteRule{
        override def transform(node:xml.Node) = {
            if((node \ "groupId").text == "joda-time") xml.NodeSeq.Empty else node
        }
    })
}

为参考完整build.sbt

scalaVersion := "2.9.2"

crossScalaVersions := Seq("2.9.2", "2.10.0-RC5")

unmanagedSourceDirectories in Compile <+= (sourceDirectory in Compile, scalaVersion){ (s,v) => s / ("scala-"+v) }

libraryDependencies += "joda-time" % "joda-time" % "1.6.2"

libraryDependencies += "org.mindrot" % "jbcrypt" % "0.3m"

pomPostProcess := {
    import xml.transform._
    new RuleTransformer(new RewriteRule{
        override def transform(node:xml.Node) = {
            if((node \ "groupId").text == "joda-time") xml.NodeSeq.Empty else node
        }
    })
}


Answer 2:

我做过类似这样与SBT东西为例: https://github.com/seanparsons/scalaz/commit/21298eb4af80f107181bfd09eaaa51c9b56bdc28

它是由可以通过SBT允许基于其他设置,这意味着大多数其他的事情应该“只是工作”,以确定所有设置。

至于pom.xml的方面,我只能建议,要求在SBT邮件列表的问题,我会感到惊讶,如果你不能做到这一点不过。



Answer 3:

我的博客文章http://www.day-to-day-stuff.blogspot.nl/2013/04/fixing-code-and-binary.html包含用于连接不同来源的目录稍微更细粒度的解决方案的示例; 每个大S.一个还解释了如何创建可以通过特定的代码不被使用的Scala版本特定的代码。

更新2016年11月8日 :SBT现在支持这一开箱: http://www.scala-sbt.org/0.13/docs/sbt-0.13-Tech-Previews.html#Cross-version+support+for+斯卡拉+源



文章来源: How to support multiple Scala versions in a library