通过试验和可能的错误,作为插件作者,我已经使用以下样式,这似乎有效:
object AmazingPlugin extends AutoPlugin {
object autoImport {
val amaze = TaskKey[Amazement]("Do something totally effing amazing")
}
import autoImport._
lazy val ethDefaults : Seq[sbt.Def.Setting[_]] = Seq(
amaze in Compile := { amazeTask( Compile ).value },
amaze in Test := { amazeTask( Test ).value }
)
def amazeTask( config : Configuration ) : Initialize[Task[Amazement]] = Def.task {
???
}
}
不幸的是,我实际上并不了解所有这些构造是如何工作的,例如为什么它是一个Initialize[Task[T]]
I 生成而不是一个Task[T]
. 我假设这个成语“做正确的事”,我认为这意味着该amazeTask
函数为每个生成一些不可变任务的包装器或种子或生成器,Configuration
并将其绑定到适当的任务键一次。但这对我来说是完全不透明的。例如,当我查找Initialize时,我看到一个value
需要参数的方法,我在上面的成语中没有提供该参数。我假设在设计 SBT 配置时使用了带有隐式和/或宏的 DSL 技巧,并且对此不以为然。
但是,最近我想将我的任务中的一些逻辑分解为逻辑上私有的函数,但也需要访问任务和设置的值。如果只使用私有函数,收集所有参数将成为表单的重复样板
val setting1 = (setting1 in config).value
val setting2 = (setting2 in config).value
...
val settingN = (settingN in config).value
val derivedValue = somePrivateFunction( setting1, setting2 ... settingN )
我需要使用的任何地方都可以从设置中获取值。所以最好将所有这些因素都纳入一项derivedValue
任务,我可以将上述所有内容替换为
derivedValue.value
科尔。
但我确实想derivedValue
保密,所以我不将它绑定到任务键。我只是这样做:
private def findDerivedValueTask( config : Configuration ) : Initialize[Task[DerivedValue]] = Def.task {
val setting1 = (setting1 in config).value
val setting2 = (setting2 in config).value
...
val settingN = (settingN in config).value
somePrivateFunction( setting1, setting2 ... settingN )
}
现在它可以很好地实现我真正的公共任务......
def amazeTask( config : Configuration ) : Initialize[Task[Amazement]] = Def.task {
val derivedValue = findDerivedValueTask( config ).value
// do stuff with derivedValue that computes and Amazement object
???
}
伟大的!它确实工作得很好。
但是我很难假设这个习语有一些魔法可以做正确的事情,那就是Task
每个配置只生成一个不可变对象并重用它。所以,我对自己想,我应该记住这个findDerivedValueTask
函数,这样在它生成一个任务之后,这个任务就会被存储在 a 中Map
,它的键是Configuration
s,但它的值在逻辑上Task
是 s。
但现在我不理解幕后发生的事情。我应该存储Initialize[Task[DerivedValue]]
还是只存储Task[DerivedValue]
,还是什么?我是否需要打扰,sbt 是否有一些聪明的魔法已经在为我处理这个问题?我真的只是不知道。
如果你已经读到这里,我非常感激。如果您能澄清这一点,或者向我指出解释这些东西如何工作的文档,我将更加感激。谢谢!