我在SBT中有一些设置,我需要在加载的插件执行一些副作用后生成值。 onLoad
钩子似乎是最好的选择。钩子接收State
,转换它并返回一个新的。使用State
方法安排命令很容易,但更改设置似乎并不容易。
我首先尝试了以下代码,但是它失败了,因为它似乎导致对onLoad
的递归调用以及由于重复的actor名称(可能是递归的产物)导致的失败。
onLoad in Global := (onLoad in Global).value andThen { state =>
val settings = generateMySettings
Project.extract(state).append(settings, state)
}
我看到的另一种选择是直接调用put
本身中的update
或State
方法,但这看起来非常难看并且容易出错。有更好/更清洁的方式吗?
答案 0 :(得分:2)
有一个很好的例子说明如何重新布线"在github sbt repo:https://github.com/sbt/sbt-community-plugins/blob/master/project/Dependencies.scala
的onLoad钩子上的项目设置我不确定为什么onLoad挂钩可能会被执行多次,但问题的解决方案是简单地定义一个布尔标志属性,如果标志不是,那么只能有条件地调用你的钩子一次。触发了。
在上面提到的例子中,他们正是这样做的,
trait GenerateMySettingsStartup extends Build {
private lazy val generated = AttributeKey[Boolean]("my-settings-generated")
def generateCommandName = "generate-my-settings"
private final def fixState(state: State): State =
if(state.get(generated) getOrElse false) {
state
} else {
// >>> generate and append your settings here <<<
state.put(generated, true)
}
private def initialize = Command.command(generateCommandName)(fixState(_))
final def generateSettings: Seq[Setting[_]] = Seq(
commands += initialize,
// initialize onLoad task if not yet defined
onLoad in Global <<= (onLoad in Global) ?? idFun[State],
// append generateCommandName onLoad handler
onLoad in Global <<= (onLoad in Global) apply ( _ andThen (generateCommandName :: _))
)
}
然后只需将GenerateMySettingsStartup#generateSettings应用到项目的设置中。
P.S。我不确定我是否已经做好了,但是在这里我认为onLoad钩子是通过Command定义的,因为它可以访问一个可能没有在某些范围内定义的状态,只是一个疯狂的猜测,所以如果我的假设可以澄清我是错的,谢谢!