首页 > 解决方案 > SBT插件:在运行taskKey之前使用inputTask覆盖settingKey?

问题描述

我有一个taskwhich takesettingA和 settingB` 作为运行的输入。

我想要一个inputTask可以覆盖settingAtask使用新值运行的settingA.

如何做到这一点?

谢谢你。

更多细节:

任务将类似于:

Def.taskDyn {
   val settingAValue = settingA.value
   val settingBValue = settingB.value

   Def.task {
      settingAValue + settingBValue
   }
}

人们会在他们的build.sbt

settingA := 3
settingB := 1

然后sbt task会产生4

我想要一个inputTask赞:

Def.inputTaskDyn {
  val newValue = customParser.parsed

  Def.taskDyn {
     val settingCValue = settingC.value

     Def.task {
        // call task with settingA = newValue ? 
     }
  }
}

编辑:

如果这样更容易,settingA可能是 aTask而不是 a Setting

标签: scalasbt

解决方案


你可以这样做:

lazy val setting1 = settingKey[String]("")
lazy val setting2 = settingKey[String]("")

lazy val task1 = taskKey[Unit]("")
lazy val inputTask1 = inputKey[Unit]("")

setting1 := "a"
setting2 := "b"

task1 := {
  println(setting1.value + setting2.value)
}

inputTask1 := {
  val newValue = Parsers.spaceDelimited("arg").parsed.head
  val curState = state.value
  val updState = Project.extract(curState).appendWithoutSession(
    Vector(setting1 := newValue),
    curState
  )
  Project.extract(updState).runTask(task1, updState)
}

基本上,您可以依赖 SBT 构建状态是完全可自省的这一事实,并且可以对其进行修改并以新状态运行任务。

但是,文档建议不要在任务中使用它。一般来说,SBT 模型是所有设置实际上都是不可变的——您不能也不应该在任务执行期间修改它们。相反,建议为此使用命令

commands += command1

lazy val command1 = Command.args("command1", "") { (state, args) =>
  val updState = Project.extract(state).appendWithoutSession(
    Vector(setting1 := args.head),
    state
  )
  val (finalState, _) = Project.extract(updState).runTask(task1, updState)
  finalState
}

请注意,此命令setting1在执行后保留设置为提供的值。如果您不想这样做,则应返回原始状态值,或者更好的是,将原始值保存setting1到局部变量并在任务运行后将其恢复:

lazy val command1 = Command.args("command1", "") { (state, args) =>
  val newValue = args.head
  val originalValue = Project.extract(state).get(setting1)

  val updState = Project.extract(state).appendWithoutSession(
    Vector(setting1 := newValue),
    state
  )
  val (nextState, _) = Project.extract(updState).runTask(task1, updState)

  Project.extract(nextState).appendWithoutSession(
    Vector(setting1 := originalValue),
    nextState
  )
}

不幸的是,API 不是很直观(例如你必须调用Project.extract很多),但它是做你想做的事的正确方法。请注意,可以通过多种方式构造命令,包括您拥有自己的Parser; 为了简单起见,我在Command.args上面使用过。


推荐阅读