如何在前缀中定义sbt插件任务而不与全局范围冲突?

Tim*_*lim 5 scala sbt

我正在尝试使用插件范围内的任务编写插件(例如:"my-plugin:update").这是我的示例代码(sbt 0.13.0):

import sbt._
import Keys._

object MyPlugin extends Plugin
{
  lazy val conf = config("my-plugin")
  val update = taskKey[Unit]("Wow!.") in conf
  override lazy val settings = inConfig(conf)(Seq(
    update := println("wow")
  ))
}
Run Code Online (Sandbox Code Playgroud)

但是当我尝试使用这个插件时,我收到了这个错误:

检测到AttributeKey ID冲突:'update'(sbt.Task [Unit],sbt.Task [sbt.UpdateReport])

是否可以在没有冲突的情况下在插件范围内定义任务?

Eug*_*ota 4

对您问题的快速回答是,不,您不能定义名称为 的任务键"update"

为了解决这个问题,那些参与插件命名空间的人:有一个好的解决方案吗?与人合着的插件最佳实践,至今仍然有效。请参阅避免命名空间冲突部分:

避免命名空间冲突

有时,您需要一个新密钥,因为没有现有的 sbt 密钥。在这种情况下,请在 sbt 命名空间和 Scala val 中使用的(字符串)键名中使用特定于插件的前缀。有两种可接受的方法可以实现这一目标。

只需使用 val 前缀

package sbtobfuscate
object Plugin extends sbt.Plugin {
  val obfuscateStylesheet = settingKey[File]("Obfuscate stylesheet")
}
Run Code Online (Sandbox Code Playgroud)

在这种方法中,每个 val 都以混淆开始。该插件的用户会参考如下设置:

obfuscateStylesheet := ...
Run Code Online (Sandbox Code Playgroud)

使用嵌套对象

package sbtobfuscate
object Plugin extends sbt.Plugin {
  object ObfuscateKeys {
    val stylesheet = SettingKey[File]("obfuscateStylesheet")
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种方法中,所有非通用设置都位于嵌套对象中。该插件的用户会参考如下设置:

import ObfuscateKeys._ // place this at the top of build.sbt

stylesheet := ...
Run Code Online (Sandbox Code Playgroud)

我认为选择取决于您的偏好以及您要定义的键的数量。对于 sbt-buildinfo ,为了简单起见,我选择使用“仅使用 val 前缀”方法,但对于任何其他插件,我选择“使用嵌套对象”方法,包括sbt-assemble

有关更多详细信息,另请参阅Mark 的帖子

:3。相关的是,配置是对插件设置进行分组的错误轴。使用插件的主要任务(例如“程序集”)来执行此操作。否则我只能在每个项目中轻松使用你的插件一次。这对于某些插件来说可能没问题,但它是不必要的限制。

:4。范围不是命名空间。对于任何给定的键名,只能有一种类型。也就是说,你不能:

SettingKey[Int]("value")
Run Code Online (Sandbox Code Playgroud)

SettingKey[Double]("value")
Run Code Online (Sandbox Code Playgroud)

仅当两个不同的插件定义相同的键/类型时,将键放入嵌套对象中才有帮助,因此在 Scala 标识符级别,它是不明确的:

object A extends Plugin {
  val a = SettingKey[Int]("a")
}
object B extends Plugin {
  val a = SettingKey[Int]("a")
}

// ambiguous in a build.sbt
a := 3
Run Code Online (Sandbox Code Playgroud)

正确的解决方案是 a) 重用内置密钥和 b) 定义公共密钥库。按键是设置系统的界面。