问题 如何在SBT 1.0中更改项目的ID?


我有一堆SBT 0.13项目定义,如下所示:

lazy val coreBase = crossProject.crossType(CrossType.Pure).in(file("core"))
  .settings(...)
  .jvmConfigure(_.copy(id = "core"))
  .jsConfigure(_.copy(id = "coreJS"))

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

(主要是因为我对于必须维护Scala.js构建并且不想输入它感到不满 JVM 每当我改变项目时后缀等等)

这不能在SBT 1.0中编译,因为 Project 没有 copy 方法吧。

好的,我们来检查一下 迁移指南

许多案例类被替换为使用Contraband生成的伪案例类。迁移 .copy(foo = xxx) 至 withFoo(xxx)

很酷,我们来试试吧。

build.sbt:100: error: value withId is not a member of sbt.Project
  .jvmConfigure(_.withId("core"))
                  ^

所以我 在吉特问道 并得到了蟋蟀。

1.0 API文档的链接现在实际上指向了某些东西,这很好,但它们并没有很大帮助 这个案例,并试图阅读SBT来源让我头疼。我并不急于更新到1.0,但我想在某些时候,我想,也许有些有帮助的人会在那时回答这个问题。


5749
2017-09-18 04:13


起源



答案:


(这个答案已经编辑了有关sbt 1.1.0+和sbt-crossproject 0.3.1+的信息,这显着简化了整个事情。)

使用sbt 1.1.0及更高版本,您可以使用 .withId("core")。但是对于sbt-crossproject 0.3.1+更好,见下文。

我不知道改变一个的ID Project但是 这也是一种完全不同的解决原始问题的方法,即有 core/coreJS 代替 coreJVM/coreJS。想法是定制 crossProject 使用您想要开始的ID。

首先,你需要使用 SBT-crossproject。它是跨多个平台进行编译的新“标准”,由Scala Native和我自己(来自Scala.js)的@densh共同设计。 Scala.js 1.x将始终使用sbt-crossproject,但也可以将sbt-crossproject与Scala.js 0.6.x一起使用。为此,请关注 自述文件中的说明。特别是,不要忘记“阴影”部分:

// Shadow sbt-scalajs' crossProject and CrossType from Scala.js 0.6.x
import sbtcrossproject.{crossProject, CrossType}

sbt-crossproject比Scala.js的硬编码更灵活 crossProject。这意味着您可以更轻松地自定义它。特别是,它有一个通用的概念 Platform,定义任何给定平台的行为方式。

对于跨JVM / JS项目,新风格 crossProject 调用将是

lazy val coreBase = crossProject(JVMPlatform, JSPlatform)
  .crossType(CrossType.Pure)
  .in(file("core"))
  .settings(...)
  .jvmConfigure(_.copy(id = "core"))
  .jsConfigure(_.copy(id = "coreJS"))

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

从sbt-crossproject 0.3.1开始,您可以简单地告诉它不要为您的某个平台添加平台后缀。在您的情况下,您希望避免JVM平台的后缀,因此您可以编写:

lazy val coreBase = crossProject(JVMPlatform, JSPlatform)
  .withoutSuffixFor(JVMPlatform)
  .crossType(CrossType.Pure)
  ...

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

这就是你需要做的一切!

旧答案,适用于sbt-crossproject 0.3.0及之前

JVMPlatform 和 JSPlatform 不是ADT;它们采用OO风格设计。这意味着您可以创建自己的。特别是,您可以创建自己的 JVMPlatformNoSuffix 这将做同样的事情 JVMPlatform 但是没有为项目ID添加后缀:

import sbt._
import sbtcrossproject._

case object JVMPlatformNoSuffix extends Platform {
  def identifier: String = "jvm"
  def sbtSuffix: String = "" // <-- here is the magical empty string
  def enable(project: Project): Project = project
  val crossBinary: CrossVersion = CrossVersion.binary
  val crossFull: CrossVersion = CrossVersion.full
}

现在还不够,因为 .jvmSettings(...) 和朋友被定义为采取行动 JVMPlatform,而不是任何其他 Platform 如 JVMPlatformNoSuffix。因此,你必须重新定义它:

implicit def JVMNoSuffixCrossProjectBuilderOps(
    builder: CrossProject.Builder): JVMNoSuffixCrossProjectOps =
  new JVMNoSuffixCrossProjectOps(builder)

implicit class JVMNoSuffixCrossProjectOps(project: CrossProject) {
  def jvm: Project = project.projects(JVMPlatformNoSuffix)

  def jvmSettings(ss: Def.SettingsDefinition*): CrossProject =
    jvmConfigure(_.settings(ss: _*))

  def jvmConfigure(transformer: Project => Project): CrossProject =
    project.configurePlatform(JVMPlatformNoSuffix)(transformer)
}

一旦你在你的构建中拥有所有这些(隐藏在一个 project/JVMPlatformNoSuffix.scala 为了不污染 .sbt 文件),您可以将上面的跨项目定义为:

lazy val coreBase = crossProject(JVMPlatformNoSuffix, JSPlatform)
  .crossType(CrossType.Pure)
  .in(file("core"))
  .settings(...)

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

无需明确修补项目ID。


15
2017-09-18 09:58



我创建 github.com/scala-native/sbt-crossproject/pull/61 实现这个想法。我认为这种模式足以将其直接包含在插件中。 - Guillaume Massé
再次感谢@sjrd!我接受这个答案,但如果有人有一个简单的方法来改变 id 直接我有兴趣看到它。 - Travis Brown
修正了即将到来的sbt 1.1顺便说一下: github.com/sbt/sbt/pull/3601。 - Dale Wijnand
@TravisBrown我更新了sbt 1.1.0+和sbt-crossproject 0.3.1+的答案,两者都显着简化了解决方案。 - sjrd


答案:


(这个答案已经编辑了有关sbt 1.1.0+和sbt-crossproject 0.3.1+的信息,这显着简化了整个事情。)

使用sbt 1.1.0及更高版本,您可以使用 .withId("core")。但是对于sbt-crossproject 0.3.1+更好,见下文。

我不知道改变一个的ID Project但是 这也是一种完全不同的解决原始问题的方法,即有 core/coreJS 代替 coreJVM/coreJS。想法是定制 crossProject 使用您想要开始的ID。

首先,你需要使用 SBT-crossproject。它是跨多个平台进行编译的新“标准”,由Scala Native和我自己(来自Scala.js)的@densh共同设计。 Scala.js 1.x将始终使用sbt-crossproject,但也可以将sbt-crossproject与Scala.js 0.6.x一起使用。为此,请关注 自述文件中的说明。特别是,不要忘记“阴影”部分:

// Shadow sbt-scalajs' crossProject and CrossType from Scala.js 0.6.x
import sbtcrossproject.{crossProject, CrossType}

sbt-crossproject比Scala.js的硬编码更灵活 crossProject。这意味着您可以更轻松地自定义它。特别是,它有一个通用的概念 Platform,定义任何给定平台的行为方式。

对于跨JVM / JS项目,新风格 crossProject 调用将是

lazy val coreBase = crossProject(JVMPlatform, JSPlatform)
  .crossType(CrossType.Pure)
  .in(file("core"))
  .settings(...)
  .jvmConfigure(_.copy(id = "core"))
  .jsConfigure(_.copy(id = "coreJS"))

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

从sbt-crossproject 0.3.1开始,您可以简单地告诉它不要为您的某个平台添加平台后缀。在您的情况下,您希望避免JVM平台的后缀,因此您可以编写:

lazy val coreBase = crossProject(JVMPlatform, JSPlatform)
  .withoutSuffixFor(JVMPlatform)
  .crossType(CrossType.Pure)
  ...

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

这就是你需要做的一切!

旧答案,适用于sbt-crossproject 0.3.0及之前

JVMPlatform 和 JSPlatform 不是ADT;它们采用OO风格设计。这意味着您可以创建自己的。特别是,您可以创建自己的 JVMPlatformNoSuffix 这将做同样的事情 JVMPlatform 但是没有为项目ID添加后缀:

import sbt._
import sbtcrossproject._

case object JVMPlatformNoSuffix extends Platform {
  def identifier: String = "jvm"
  def sbtSuffix: String = "" // <-- here is the magical empty string
  def enable(project: Project): Project = project
  val crossBinary: CrossVersion = CrossVersion.binary
  val crossFull: CrossVersion = CrossVersion.full
}

现在还不够,因为 .jvmSettings(...) 和朋友被定义为采取行动 JVMPlatform,而不是任何其他 Platform 如 JVMPlatformNoSuffix。因此,你必须重新定义它:

implicit def JVMNoSuffixCrossProjectBuilderOps(
    builder: CrossProject.Builder): JVMNoSuffixCrossProjectOps =
  new JVMNoSuffixCrossProjectOps(builder)

implicit class JVMNoSuffixCrossProjectOps(project: CrossProject) {
  def jvm: Project = project.projects(JVMPlatformNoSuffix)

  def jvmSettings(ss: Def.SettingsDefinition*): CrossProject =
    jvmConfigure(_.settings(ss: _*))

  def jvmConfigure(transformer: Project => Project): CrossProject =
    project.configurePlatform(JVMPlatformNoSuffix)(transformer)
}

一旦你在你的构建中拥有所有这些(隐藏在一个 project/JVMPlatformNoSuffix.scala 为了不污染 .sbt 文件),您可以将上面的跨项目定义为:

lazy val coreBase = crossProject(JVMPlatformNoSuffix, JSPlatform)
  .crossType(CrossType.Pure)
  .in(file("core"))
  .settings(...)

lazy val core = coreBase.jvm
lazy val coreJS = coreBase.js

无需明确修补项目ID。


15
2017-09-18 09:58



我创建 github.com/scala-native/sbt-crossproject/pull/61 实现这个想法。我认为这种模式足以将其直接包含在插件中。 - Guillaume Massé
再次感谢@sjrd!我接受这个答案,但如果有人有一个简单的方法来改变 id 直接我有兴趣看到它。 - Travis Brown
修正了即将到来的sbt 1.1顺便说一下: github.com/sbt/sbt/pull/3601。 - Dale Wijnand
@TravisBrown我更新了sbt 1.1.0+和sbt-crossproject 0.3.1+的答案,两者都显着简化了解决方案。 - sjrd