How to make a sbt task use a specific configuratio

2019-02-08 20:24发布

问题:

I have a task lazy val task = TaskKey[Unit] that takes a lazy val setting = SettingKey[String] as input. I also have three different, independent config scopes (config("dev"), config("stage"), config("prod")) and a build.sbt file that specifies different values for setting for each of the config scopes (setting in stage := "foo" ... ).

I expected that calling task using the config scope prefix would make the task use the values from the respective config scope (e.g. >dev:task would make the task use the setting values from dev, using command >stage:task would make the task use the setting values from stage, ...). However, this does not seem to work.

How can I force task to use the settings from a specific config scope?

build.sbt:

setting := "default setting"

setting in stage := "stage setting"

setting in prod  := "prod setting"

Build.scala:

import sbt._
import Keys._

object TaskBuild extends Build {
  val setting = SettingKey[String]("setting", "a simple string setting")

  val task = TaskKey[Unit]("task", "a simple task experiment")

  val taskTask = task <<= setting map { s: String =>
    println("Setting is: " + s)
  }

  lazy val dev = config("dev") describedAs("dev environment settings")
  lazy val stage = config("stage") describedAs("stage environment settings")
  lazy val prod = config("prod") describedAs("prod environment settings")

  lazy val root = Project(
    "project",
     file("."),
     settings = Defaults.defaultSettings ++ Seq(taskTask)
  )
  .configs(dev, stage, prod)
}

回答1:

I think you need to write something like

val devTaskSetting = task <<= setting in dev map { s: String =>
   println("Setting in Dev is: " + s)
}

You can also define separate task keys, like this

val devTask   = TaskKey[Unit]("task", "a simple task experiment") in dev
val stageTask = TaskKey[Unit]("task", "a simple task experiment") in stage


回答2:

As discussed in How can i make an SBT key see settings for the current configuration?, you can probably use inConfig as follows.

Change this:

settings = Defaults.defaultSettings ++ Seq(taskTask)

to this:

settings = Defaults.defaultSettings ++
  Seq(taskTask) ++
  inConfig(dev)(Seq(taskTask)) ++
  inConfig(stage)(Seq(taskTask)) ++
  inConfig(prod)(Seq(taskTask))

and voilà:

$ sbt
> task
Setting is: default setting
> dev:task
Setting is: default setting
> stage:task
Setting is: stage setting
> prod:task
Setting is: prod setting

If you're interested in digging deeper, inConfig is defined in sbt.Project ( http://harrah.github.io/xsbt/latest/api/index.html#sbt.Project$ ) as a function to "copy a subgraph of tasks/settings into different scopes" (as @MarkHarrah describes it). Also, take a look at http://eed3si9n.com/sbt-010-guide and scroll down to "changing the scopes" where the author explains how inConfig(conf)(ss) "scopes the settings ss in to conf only when it isn't scoped yet to a configuration".