问题
I have some settings in SBT that I need to generate values from after a loaded plugin has performed some side-effects. The onLoad
hooks seem the best place to do that. The hook receives a State
, transforms it and returns a new one. It's easy to schedule commands with State
methods, but changing settings doesn't seem very easy.
I first tried the following code, which fails because it seems to cause a recursive call to onLoad
and a failure due to a duplicate actor name (probably a product of the recursion).
onLoad in Global := (onLoad in Global).value andThen { state =>
val settings = generateMySettings
Project.extract(state).append(settings, state)
}
The other alternative I see is calling the put
or update
methods in State
itself directly, but that seems quite ugly and error prone. Is there a better/cleaner way?
回答1:
There is a good example of how to "rewire" project settings in onLoad hook at github sbt repo: https://github.com/sbt/sbt-community-plugins/blob/master/project/Dependencies.scala
I'm not sure why the onLoad hook might be executed more than one time, but the solution to your problem is to simply define a boolean flag attribute to conditionally call your hook only once if the flag wasn't triggered yet.
In the mentioned example they're doing it exactly like this,
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 :: _))
)
}
then just apply GenerateMySettingsStartup#generateSettings to your project's settings.
P.S. Not sure if I've got it all right, but here I think the onLoad hook was defined through Command because it has access to a State which might not be defined at certain scopes, just a wild guess so clarify me if my assumption is wrong, thanks!
来源:https://stackoverflow.com/questions/27760279/how-can-i-apply-setting-changes-on-onload-hook-in-sbt