2015-01-03 39 views
2

我在SBT中有一些設置,我需要在加載的插件執行一些副作用後生成值。 onLoad掛鉤似乎是最好的選擇。掛鉤接收State,轉換它並返回一個新的。使用State方法可以很容易地安排命令,但更改設置似乎並不容易。如何在SBT中的onLoad掛鉤上應用設置更改?

我第一次嘗試下面的代碼,它失敗了,因爲它似乎導致onLoad的遞歸調用和由於重複的演員名稱(可能是遞歸的產物)失敗。

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

另一種選擇我看到的是調用State本身直接putupdate方法,但似乎相當難看,而且容易出錯。有更好的/更清潔的方式嗎?

回答

2

還有就是如何在github上SBT回購「重新連接」中的onLoad掛鉤項目設置一個很好的例子: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定義的,因爲它可以訪問一個可能不在某些範圍內定義的狀態,只是一個瘋狂的猜測,所以如果我的假設是錯誤的, 謝謝!

+0

我並沒有積極地參與我想要的項目,當時我只是設置了一個命令並在啓動時用'.sbtrc'運行了它。雙重加載有點煩人,但可以承受。這看起來好多了,接近我所問的,因爲它可能是可以實現的。如果我有機會,我一定會利用它。謝謝! – danielkza