如何在SBT中的onLoad挂钩上应用设置更改?

时间:2015-01-03 22:35:57

标签: scala sbt

我在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本身中的updateState方法,但这看起来非常难看并且容易出错。有更好/更清洁的方式吗?

1 个答案:

答案 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定义的,因为它可以访问一个可能没有在某些范围内定义的状态,只是一个疯狂的猜测,所以如果我的假设可以澄清我是错的,谢谢!