如何在库中支持多个Scala版本 [英] How to support multiple Scala versions in a library

查看:75
本文介绍了如何在库中支持多个Scala版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个相当正常的 Scala项目当前正在使用Maven构建.我想同时支持Scala 2.9.x和即将发行的2.10,它们与二进制文件或源代码都不兼容.如有必要,我愿意接受转换为SBT的操作,但是我遇到了一些挑战.

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.

我对此项目的要求是:

  • 单个源树(无分支).我相信,尝试为每个Scala版本支持多个并发的主"分支将是错过分支之间的错误修正的最快方法.

  • 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.

版本特定的源目录.由于Scala版本与源代码不兼容,因此我需要能够为特定于版本的源指定辅助源目录.

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.

版本特定的源jar.最终用户应该能够为其IDE集成的Scala版本下载具有正确版本特定源的正确源jar.

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.

集成部署.我目前使用Maven发布插件将新版本部署到Sonatype OSS存储库,并希望有一个类似的简单发布工作流.

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.

最终用户Maven支持.我的最终用户通常是Maven用户,因此准确反映依赖关系的功能性POM至关重要.

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

阴影罐支持.我需要能够生成一个包含我的依赖项子集的JAR,并从已发布的POM中删除阴影的依赖项.

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.

我尝试过的事情:

  • Maven配置文件.我创建了一组Maven配置文件,以控制使用哪个版本的Scala进行构建,并使用Maven生成帮助器插件选择特定于版本的源代码树.在发布之前,它一直运行良好;

  • 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;

  • 使用分类器限定版本效果不佳,因为源jar也需要自定义分类器('source-2.9.2'等),并且大多数IDE工具都不知道如何定位他们.

  • 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.

我尝试使用Maven属性将SBT样式的_ $ {scala.version}后缀添加到工件名称,但是Maven不喜欢工件名称中的属性.

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.一旦可以使用它,此方法就很好用(尽管有大量文档,但也不是一件容易的事).缺点是似乎没有Maven阴影插件等效.我看过:

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.该插件未针对SBT 0.12.x进行更新,并且不会从源代码生成,因为它依赖于另一个更改了groupIds且未使用旧名称的0.12.x版本的SBT插件.我还无法解决如何指示SBT忽略/替换插件依赖项的问题.

  • 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.这使用自定义类加载来从嵌入式jar中运行Main类,这不是期望的结果.我希望我项目的类文件与阴影依赖项中的(可能重命名的)类文件一起放在jar中.

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程序集插件.这可以在一定程度上起作用,但是POM文件似乎包含我要隐藏的依赖项,这对最终用户没有帮助.

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.

我接受可能没有一种解决方案可以满足我对Scala的要求,并且/或者我可能需要编写自己的Maven或Scala插件来实现目标.但是,如果可以的话,我想找到一个现有的解决方案.

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.

我几乎要接受@ Jon-Ander出色的答案,但是对我来说仍然有一件出色的作品,是一个统一的发布过程.我的 build.sbt的当前状态在GitHub . (我将在后面的答案中为后代在此复制它.)

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).

sbt-release插件不支持多版本构建(即,+ release的行为不尽人意),这在某种意义上是因为发行标记过程实际上并不需要发生版本.但是我希望流程的两个部分是多版本的:测试和发布.

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.

我想发生的事情类似于两阶段的maven-release-plugin过程.第一阶段将完成更新Git并运行测试的管理工作,在这种情况下,这意味着运行+ test,以便对所有版本进行测试,标记,更新为快照,然后将结果推送到上游.

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.

第二阶段将检出标记的版本和+ publish,这将重新运行测试并将标记的版本推送到Sonatype存储库.

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值,但是我不确定我是否可以在build.sbt中支持多个releaseProcess值.它可能可以与其他一些示波器一起使用,但是SBT的那部分对我来说仍然很奇怪.

I suspect that I could write releaseProcess values that do each of these, but I'm not sure if I can support multiple releaseProcess values in my build.sbt. It probably can work with some additional scopes, but that part of SBT is still strange majick to me.

我目前所做的是将releaseProcess更改为不发布.然后,我必须手动检出标记的版本,然后在事实之后运行+ publish,这与我想要的接近,但确实会妥协,特别是因为测试仅在发布过程中在当前的scala版本上运行.我可以接受一个不像maven插件那样分两个阶段的过程,但是可以实现多版本测试和发布.

What I currently have done is changed the releaseProcess to not publish. I then have to checkout the tagged version by hand and run + publish after the fact, which is close to what I want but does compromise, especially since the tests are only run on the current scala version in the release process. I could live with a process that isn't two-stage like the maven plugin, but does implement multi-version test and publish.

任何能使我走到最后一英里的反馈都将不胜感激.

Any additional feedback that can get me across the last mile would be appreciated.

推荐答案

单个来源树中的sbt都很好地支持了这一点

Most of this is well supported in sbt within a single source tree

版本特定的源目录通常是不需要的. Scala程序往往是源兼容的-实际上经常如此 交叉构建( http://www.scala-sbt.org/release /docs/Detailed-Topics/Cross-Build )在sbt中具有一流的支持.

Version specific source directories are usually not need. Scala programs tends to be source compatible - so often in fact that crossbuilding (http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build) has first class support in sbt.

如果您确实需要特定于版本的代码,则可以添加额外的源文件夹. 将其放入您的build.sbt文件中,除了常规的"src/main/scala"之外,还将在交叉构建时为每个版本的源目录添加"src/main/scala- [scalaVersion]". (也有一个可用于在版本之间生成填充的插件,但是我还没有尝试过- https://github.com/sbt/sbt-scalashim )

If you really need version specific code, you can add extra source folders. Putting this in your build.sbt file will add "src/main/scala-[scalaVersion]" as a source directory for each version as you crossbuild in addition to the regular "src/main/scala". (there is also a plugin available for generating shims between version, but I haven't tried it - https://github.com/sbt/sbt-scalashim)

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

特定于版本的源jar-见交叉构建,即用即用

version specific source jars - see crossbuilding, works out of the box

集成部署- https://github.com/sbt/sbt-release (已很棒的git集成)

integrated deployment - https://github.com/sbt/sbt-release (has awesome git integration too)

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

Maven end-users - http://www.scala-sbt.org/release/docs/Detailed-Topics/Publishing.html

阴影-我已经使用了这个 https://github.com/sbt/sbt-assembly可以很好地满足我的需求. 您可以通过重写生成的pom来解决Assembly插件的问题. 这是删除joda-time的示例.

Shaded - I have used this one https://github.com/sbt/sbt-assembly which have worked fine for my needs. Your problem with the assembly plugin can be solved by rewriting the generated pom. Here is an example ripping out joda-time.

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供参考

Complete build.sbt for for reference

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
        }
    })
}

这篇关于如何在库中支持多个Scala版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆