1. 從 sbt 0.13.x 遷移

從 sbt 0.13.x 遷移 

遷移 case class .copy(...) 

許多 case class 已被使用 Contraband 產生的偽 case class 取代。請將 .copy(foo = xxx) 遷移至 withFoo(xxx)。假設您有 m: ModuleID,並且您目前正在呼叫 m.copy(revision = "1.0.1")。以下是如何遷移的方法

m.withRevision("1.0.1")

SbtPlugin 

sbt 0.13、sbt 1.0 和 sbt 1.1 需要 sbtPlugin 設定和腳本外掛程式來開發 sbt 外掛程式。sbt 1.2.1 將兩者合併到 SbtPlugin 外掛程式中。

請從 project/plugins.sbt 移除 scripted-plugin,並僅使用

lazy val root = (project in file("."))
  .enablePlugins(SbtPlugin)

sbt 版本特定原始碼目錄 

如果您正在跨平台建置 sbt 外掛程式,我們有一個權宜之計是使用 sbt 版本特定原始碼目錄 src/main/scala-sbt-0.13src/main/scala-sbt-1.0。您可以在其中定義一個名為 PluginCompat 的物件,如下所示

package sbtfoo

import sbt._
import Keys._

object PluginCompat {
  type UpdateConfiguration = sbt.librarymanagement.UpdateConfiguration

  def subMissingOk(c: UpdateConfiguration, ok: Boolean): UpdateConfiguration =
    c.withMissingOk(ok)
}

現在可以在 sbt 版本特定的方式中實作 subMissingOk(...) 函式。

遷移至斜線語法 

在 sbt 0.13 中,鍵值使用 2 種不同的語法來限定範圍:一種用於 sbt 的 shell,另一種用於程式碼中。

  • sbt 0.13 shell:<project-id>/config:intask::key
  • sbt 0.13 程式碼:key in (<project-id>, Config, intask)

從 sbt 1.1.0 開始,限定鍵值範圍的語法已統一用於 shell 和建置定義,使用斜線語法,如下所示

  • <project-id> / Config / intask / key

以下是一些範例

version in ThisBuild := "1.0.0-SNAPSHOT"

lazy val root = (project in file("."))
  .settings(
    name := "hello",
    scalacOptions in Compile += "-Xlint",
    scalacOptions in (Compile, console) --= Seq("-Ywarn-unused", "-Ywarn-unused-import"),
    fork in Test := true
  )

現在可以寫成

ThisBuild / version := "1.0.0-SNAPSHOT"

lazy val root = (project in file("."))
  .settings(
    name := "hello",
    Compile / scalacOptions += "-Xlint",
    Compile / console / scalacOptions --= Seq("-Ywarn-unused", "-Ywarn-unused-import"),
    Test / fork := true
  )

現在在 sbt 的 shell 中使用相同的語法

sbt:hello> name
[info] hello
sbt:hello> ThisBuild / version
[info] 1.0.0-SNAPSHOT
sbt:hello> show Compile / scalacOptions
[info] * -Xlint
sbt:hello> show Compile / console / scalacOptions
[info] * -Xlint
sbt:hello> Test / fork
[info] true

有一個 用於統一斜線語法的語法 Scalafix 規則,可半自動地將現有的 sbt 0.13 語法重寫為斜線語法。目前它需要使用 scalafix CLI,而且不是很精確(因為它是一個僅查看程式碼形狀的語法規則),但它可以完成大部分工作。

$ scalafix --rules=https://gist.githubusercontent.com/eed3si9n/57e83f5330592d968ce49f0d5030d4d5/raw/7f576f16a90e432baa49911c9a66204c354947bb/Sbt0_13BuildSyntax.scala *.sbt project/*.scala

從 sbt 0.12 樣式遷移 

在 sbt 0.13 之前(sbt 0.9 到 0.12),在建置中很常見到使用 sbt 的三個方面

  • 鍵相依性運算子:<<=<+=<++=
  • TaskKey 和 SettingKey 的 tuple enrichments (apply 和 map) (例如 (foo, bar) map { (f, b) => ... }
  • project/Build.scala 中使用 Build 特徵

sbt 0.13 的發佈(三年前!)引入了 .value DSL,它可以讓程式碼更容易讀寫,有效地使前兩個方面變得多餘,並從官方文件中刪除。

同樣地,sbt 0.13 引入的多專案 build.sbt 使 Build 特徵變得多餘。此外,現在在 sbt 0.13 中已成為標準的自動外掛程式功能啟用了外掛程式設定的自動排序和自動匯入功能,但它使 Build.scala 更難以維護。

由於它們已在 sbt 1.0.0 中移除,在此我們將協助您了解如何遷移您的程式碼。

遷移 sbt 0.12 樣式運算子 

對於簡單的運算式,例如

a <<= aTaskDef
b <+= bTaskDef
c <++= cTaskDefs

只需將它們替換為等效的

a := aTaskDef.value
b += bTaskDef.value
c ++= cTaskDefs.value

從 tuple enrichments 遷移 

如上所述,有兩個 tuple enrichments .apply.map。差異在於您是否正在為 SettingKeyTaskKey 定義設定,前者使用 .apply,後者使用 .map

val sett1 = settingKey[String]("SettingKey 1")
val sett2 = settingKey[String]("SettingKey 2")
val sett3 = settingKey[String]("SettingKey 3")

val task1 = taskKey[String]("TaskKey 1")
val task2 = taskKey[String]("TaskKey 2")
val task3 = taskKey[String]("TaskKey 3")
val task4 = taskKey[String]("TaskKey 4")

sett1 := "s1"
sett2 := "s2"
sett3 <<= (sett1, sett2)(_ + _)

task1 := { println("t1"); "t1" }
task2 := { println("t2"); "t2" }
task3 <<= (task1, task2) map { (t1, t2) => println(t1 + t2); t1 + t2 }
task4 <<= (sett1, sett2) map { (s1, s2) => println(s1 + s2); s1 + s2 }

(請記住,您可以用設定來定義任務,但反之則不行)

使用 .value DSL,您不必知道或記住您的鍵是否為 SettingKeyTaskKey

sett1 := "s1"
sett2 := "s2"
sett3 := sett1.value + sett2.value

task1 := { println("t1"); "t1" }
task2 := { println("t2"); "t2" }
task3 := { println(task1.value + task2.value); task1.value + task2.value }
task4 := { println(sett1.value + sett2.value); sett1.value + sett2.value }

當使用 .dependsOn.triggeredBy.runBefore 時遷移 

當改為呼叫 .dependsOn 時,請勿使用

a <<= a dependsOn b

將其定義為

a := (a dependsOn b).value

請注意:由於問題 #1444,您需要在 sbt 0.13.13 和更早的版本中使用 <<= 運算子搭配 .triggeredBy.runBefore

當您需要設定 Task 時遷移 

對於使用 sbt 的 Task 類型之鍵,例如 sourceGeneratorsresourceGenerators

val sourceGenerators =
  settingKey[Seq[Task[Seq[File]]]]("List of tasks that generate sources")
val resourceGenerators =
  settingKey[Seq[Task[Seq[File]]]]("List of tasks that generate resources")

您先前會將其定義為

sourceGenerators in Compile <+= buildInfo

對於 sbt 1,您可以將其定義為

Compile / sourceGenerators += buildInfo

或一般來說,

Compile / sourceGenerators += Def.task { List(file1, file2) }

使用 InputKey 遷移 

當使用 InputKey 時,請勿使用

run <<= docsRunSetting

在遷移時,您不得使用 .value,而應使用 .evaluated

run := docsRunSetting.evaluated

從 Build 特徵遷移 

使用基於 Build 特徵的建置,例如

import sbt._
import Keys._
import xyz.XyzPlugin.autoImport._

object HelloBuild extends Build {
  val shared = Defaults.defaultSettings ++ xyz.XyzPlugin.projectSettings ++ Seq(
    organization := "com.example",
    version      := "0.1.0",
    scalaVersion := "2.12.18")

  lazy val hello =
    Project("Hello", file("."),
      settings = shared ++ Seq(
        xyzSkipWrite := true)
    ).aggregate(core)

  lazy val core =
    Project("hello-core", file("core"),
      settings = shared ++ Seq(
        description := "Core interfaces",
        libraryDependencies ++= scalaXml.value)
    )

  def scalaXml = Def.setting {
    scalaBinaryVersion.value match {
      case "2.10" => Nil
      case _      => ("org.scala-lang.modules" %% "scala-xml" % "1.0.6") :: Nil
    }
  }
}

您可以遷移到 build.sbt

val shared = Seq(
  organization := "com.example",
  version      := "0.1.0",
  scalaVersion := "2.12.18"
)

lazy val helloRoot = (project in file("."))
  .aggregate(core)
  .enablePlugins(XyzPlugin)
  .settings(
    shared,
    name := "Hello",
    xyzSkipWrite := true
  )

lazy val core = (project in file("core"))
  .enablePlugins(XyzPlugin)
  .settings(
    shared,
    name := "hello-core",
    description := "Core interfaces",
    libraryDependencies ++= scalaXml.value
  )

def scalaXml = Def.setting {
  scalaBinaryVersion.value match {
    case "2.10" => Nil
    case _      => ("org.scala-lang.modules" %% "scala-xml" % "1.0.6") :: Nil
  }
}
  1. project/Build.scala 重新命名為 build.sbt
  2. 移除匯入陳述式 import sbt._import Keys._ 和任何自動匯入。
  3. 將所有內部定義(如 sharedhelloRoot 等)移出 object HelloBuild,並移除 HelloBuild
  4. Project(...) 變更為 (project in file("x")) 樣式,並呼叫其 settings(...) 方法來傳入設定。這是為了讓自動外掛程式可以根據外掛程式相依性重新排序其設定順序。應該設定 name 設定以保留舊名稱。
  5. 請從 shared 移除 Defaults.defaultSettings,因為這些設定已由內建的自動外掛程式設定,並從 shared 移除 xyz.XyzPlugin.projectSettings,並改為呼叫 enablePlugins(XyzPlugin)

請注意Build 特徵已過時,但您仍然可以使用 project/*.scala 檔案來組織您的建置和/或定義 ad-hoc 外掛程式。請參閱組織建置

從 Resolver.withDefaultResolvers 遷移 

在 0.13.x 中,您可以使用其他儲存庫,而不是 Maven Central 儲存庫

externalResolvers := Resolver.withDefaultResolvers(resolvers.value, mavenCentral = false)

在 1.x 之後,withDefaultResolvers 重新命名為 combineDefaultResolvers。同時,其中一個參數 userResolvers 已變更為 Vector,而不是 Seq

  • 您可以使用 toVector 來協助遷移。

    externalResolvers := Resolver.combineDefaultResolvers(resolvers.value.toVector, mavenCentral = false)
    
  • 您也可以直接使用 Vector