通过试用和可能的错误,作为插件作者,我已经陷入使用以下样式,这似乎有效:
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]]
我生成的而不是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
KEWL。
但我确实希望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
函数,以便在生成任务后,任务存储在Map
中,其密钥为Configuration
但其值为逻辑Task
s。
但现在我对幕后发生的事情的不了解。我应该存储Initialize[Task[DerivedValue]]
还是只存储Task[DerivedValue]
,还是存储什么?我是否需要打扰,是否有一些聪明的魔法已经为我照顾了这个?我真的不知道。
如果您已经读过这篇文章,我将非常感激。如果你可以清楚地说明这一点,或者指出解释这些东西如何运作的文档,我会更加感激。谢谢!