【问题标题】:SBT Plugin: Use inputTask to override settingKey before run taskKey?SBT插件:在运行taskKey之前使用inputTask覆盖settingKey?
【发布时间】:2019-05-28 05:32:12
【问题描述】:

我有一个task,它将settingA 和settingB` 作为输入来运行。

我想要一个 inputTask,它将覆盖 settingA 并使用 settingA 的新值运行 task

如何做到这一点?

谢谢。

更多详情:

任务类似于:

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 可以是 Task 而不是 Setting

【问题讨论】:

    标签: scala sbt


    【解决方案1】:

    你可以这样做:

    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

    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

    【讨论】:

    • 感谢您的帮助!您将如何在命令中使用解析器?
    • 不是保存值并重新设置它们,我不能只返回原始状态吗?
    • 请参阅Command 工厂方法 - 有些接受解析器或来自State 的函数返回解析器。是的,我想你可以返回原始状态,虽然我不知道你不返回任务调用产生的状态有多重要。
    猜你喜欢
    • 1970-01-01
    • 2013-01-18
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 2018-09-01
    • 2019-06-09
    • 2017-09-25
    相关资源
    最近更新 更多