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

时间:2013-12-01 19:27:36

标签: 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")
  ))
}

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

  

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

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

1 个答案:

答案 0 :(得分:4)

快速回答您的问题是,您无法定义名为"update"的任务键。

要解决此问题,那些参与Plugin namespacing: A good solution?合着Plugins Best Practices的人今天仍然站着。请参阅Avoid namespace clashes部分:

  

避免命名空间冲突

     

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

     

只需使用val前缀

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

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

obfuscateStylesheet := ...
     

使用嵌套对象

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

在此方法中,所有非常见设置都在嵌套对象中。一个   该插件的用户将参考如下设置:

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

stylesheet := ...

我认为选择取决于您的偏好以及您要定义的键数。对于sbt-buildinfo,我选择使用"只需使用val前缀"为了简单起见,但对于我已经去过的任何其他插件"使用嵌套对象"方法包括sbt-assembly

有关详细信息,另请参阅主题Mark's post

  

1:3。相关,配置是错误的轴分组设置   插入。使用插件的主要任务(例如' assembly')来执行此操作。    否则,每个项目我只能轻松使用一次插件。这个   某些插件可能没问题,但这是不必要的限制。

     

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

SettingKey[Int]("value")
     

SettingKey[Double]("value")
     

将密钥放在嵌套对象中只有在拥有密钥时才有用   密钥/类型由两个不同的插件定义,因此在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
     

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