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

查看:27
本文介绍了如何在一个库中支持多个 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.

我对这个项目的要求是:

My requirements for this project are:

  • 单一源代码树(无分支).我相信尝试为每个 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.最终用户应该能够为他们的 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.我需要能够生成一个 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 build-helper 插件来选择版本特定的源代码树.在发布之前一直运行良好;

  • 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 的 SBT 插件,并且在旧名称下没有 0.12.x 版本.我还没有弄清楚如何指示 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.

一个罐子.这使用自定义类加载从嵌入式 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 的行为不像人们所希望的那样),这在发布标记过程中是有道理的t 真的需要跨版本发生.但我希望流程的两个部分是多版本的:测试和发布.

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.

第二阶段将签出标记版本并 + 发布,这将重新运行测试并将标记版本推送到 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 中支持多个 releaseProcess 值.sbt.它可能可以与一些额外的范围一起使用,但是 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-scalahim)

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

版本特定的源 jars - 见交叉构建,开箱即用

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.xml 来解决.这是一个删除 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天全站免登陆