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

How can I apply setting changes on onLoad hook in SBT?

我在 SBT 中有一些设置,我需要在加载的插件执行一些副作用后生成值。 onLoad 挂钩似乎是执行此操作的最佳位置。钩子收到一个 State,将其转换并 returns 一个新的。使用 State 方法调度命令很容易,但更改设置似乎并不容易。

我首先尝试了以下代码,它失败了,因为它似乎导致对 onLoad 的递归调用,并且由于重复的参与者名称(可能是递归的产物)而失败。

onLoad in Global := (onLoad in Global).value andThen { state =>
  val settings = generateMySettings
  Project.extract(state).append(settings, state)
}

我看到的另一种选择是直接调用 State 中的 putupdate 方法,但这看起来很丑陋且容易出错。有better/cleaner方法吗?

在 github sbt repo 的 onLoad 挂钩中有一个如何 "rewire" 项目设置的好例子:https://github.com/sbt/sbt-community-plugins/blob/master/project/Dependencies.scala

我不确定为什么 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 定义的,因为它可以访问可能未在某些范围内定义的状态,这只是一个疯狂的猜测所以如果我的假设是错误的请澄清我,谢谢!