【问题标题】:Sbt task to load system environment variables加载系统环境变量的 Sbt 任务
【发布时间】:2022-02-01 14:42:52
【问题描述】:

我有一些 yaml 文件,其中包含服务运行所需的系统环境变量。

system:
  service: "name"
  port: 123

我必须在运行服务启动之前将所有这些变量加载到 shell。但我想通过一些 sbt 变量加载它们,也许是load-dev-env

我无法将用于 yaml 解析的库 (circe-yaml) 导入到 sbt shell 执行和所有导入中的主要问题

import io.circe._
import cats._

由于circe is no the subpackage of io or etc...而失败

  1. 我尝试将 libraryDependencies 放到 ./project/build.sbt - 没有成功

最后一件事 - 手动读取所有键/值,但看起来不正确

有人做过这样的事吗?

【问题讨论】:

  • 我会让服务读取文件,而不是 SBT。通过 SBT 做这件事听起来倒退了。此外,除非您只是在测试/开发,否则我不会从 SBT 运行服务。只需编译一个 JAR 文件并运行从该文件读取的服务。
  • 这不是主要需要)服务被包装到docker中,容器有环境变量,从那个配置文件中读取。因此,对于本地服务运行而不将新代码库包装到新 docker 映像中(这需要一些时间并且不喜欢花费它),我必须手动或通过一些 sbt 任务将 env 变量加载到 shell 中,它也可以是 bash 脚本来读取它))但我更喜欢 sbt 任务
  • 看起来你可以这样做(我没试过):stackoverflow.com/questions/34828688/…
  • 谢谢。以前看过并尝试过..但没有成功(

标签: scala yaml sbt


【解决方案1】:

这个SBT 构建定义有效:

目录结构:

build.sbt
src/main/resources/config.yml
project/build.sbt
project/build.properties

build.sbt:

ThisBuild / scalaVersion := "2.13.8"

ThisBuild / organization := "com.example"

lazy val hello = (project in file("."))
  .settings(
    name := "Hello",
    //libraryDependencies += "io.circe" %% "circe-yaml" % "0.14.1"
  )

lazy val loadEnv = TaskKey[Unit]("load-dev-env")
loadEnv := {
  import _root_.io.circe._
  import _root_.io.circe.yaml.parser
  import scala.io.Source
  val filename = "src/main/resources/config.yml"
  val confStr = Source.fromFile(filename).getLines.mkString("\n")
  println(confStr)
  val json: Either[ParsingFailure, Json] = parser.parse(confStr)
  println(json)
}

project/build.sbt:

libraryDependencies += "io.circe" %% "circe-yaml" % "0.14.1"

project/build.properties:

sbt.version=1.6.1

src/main/resources/config.yml:

--- 
system: 
  port: 123
  service: name

运行示例:

sbt:Hello> loadDevEnv
--- 
system: 
  port: 123
  service: name

Right({
  "system" : {
    "port" : 123,
    "service" : "name"
  }
})

它从文件中打印字符串,然后是解析的 json。

重要的细节是:

  • 您需要将库依赖项放在project 目录中的其他构建文件中。
  • 您需要使用_root_,否则如果它们不是核心 Scala 或 SBT 插件的一部分,导入将无法解析。至少我还没有找到路。

您可以在此处查看代码:https://github.com/izmailoff/sbt-import-test

--- 更新 ---:

我在 repo 中添加了完整的示例。这需要进行一些更改,因为您无法从 Task 更新 SBT 设置,您需要在 Command 中进行更新。更新文件如下:

build.sbt:

ThisBuild / scalaVersion := "2.13.8"

ThisBuild / organization := "com.example"

// This is needed to get new env values from SBT:
fork := true

lazy val hello = (project in file("."))
  .settings(
    name := "Hello",
    //libraryDependencies += "io.circe" %% "circe-yaml" % "0.14.1"
  )

commands += Command.command("loadDevEnv") { state =>
  val env = Config.getEnvFromConf()
  val envStr = Config.prettyPrint(env)
  s"set envVars ++= ${envStr}" :: state
}

project/Build.scala:

case class Service(port: Integer, service: String)

case class System(system: Service)

object Config {

    def getEnvFromConf(): Map[String, String] = {
        val filename = "src/main/resources/config.yml"
        val confStr = readConfig(filename)
        val conf = parseConfig(confStr)
        println(conf)
        val env = toEnv(conf)
        env
    }

    def readConfig(filename: String): String = {
      import scala.io.Source
      Source.fromFile(filename).getLines.mkString("\n") // use better way?
    }

    def parseConfig(conf: String): System = {
      import _root_.io.circe._
      import _root_.io.circe.yaml
      import _root_.io.circe.yaml._
      import _root_.io.circe.yaml.syntax._
      import _root_.io.circe.generic.auto._
      import cats.syntax.either._
      val json: Either[ParsingFailure, Json] = yaml.parser.parse(conf)
      json
        .leftMap(err => err: Error)
        .flatMap(_.as[System])
        .valueOr(throw _)
    }

    def toEnv(conf: System): Map[String, String] = {
      Map(s"service.${conf.system.service}" -> conf.system.port.toString)
    }

    def prettyPrint(x: Map[String, String]): String = {
      "Map(" + (x.map{ case (k, v) => s""""${k}"->"${v}""""}).mkString(", ") + ")"
    }

}

project.build.sbt:

val circeVersion = "0.14.1"

libraryDependencies ++= Seq(
  "io.circe" %% "circe-yaml",
  "io.circe" %% "circe-generic",
  "io.circe" %% "circe-parser"
).map(_ % circeVersion)

src/main/scala/Main.scala:

object Main extends App {
  println("Found the following environment variable:")
  println(System.getenv("service.name"))
}

示例:

从您的操作系统外壳运行 SBT:

> sbt

运行应用检查是否设置了环境变量:

sbt:Hello> run
[info] running (fork) Main 
[info] Found the following environment variable:
[info] null

获取null。加载环境:

sbt:Hello> loadDevEnv
[info] Defining envVars
[info] The new value will be used by Compile / bspBuildTargetRun, Compile / bspScalaMainClassesItem and 6 others.
[info]  Run `last` for details.
[info] Reapplying settings...
[info] set current project to Hello (in build file:/home/tvc/repos/sbt_test/)

运行应用再次检查:

sbt:Hello> run
[info] running (fork) Main 
[info] Found the following environment variable:
[info] 123

找到值123

【讨论】:

  • 看起来棒极了!!是的,也许_root_ 具有魔力。我会检查一下 - 非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-29
  • 1970-01-01
  • 2015-08-20
  • 2015-09-16
  • 2015-10-18
  • 2019-04-12
  • 1970-01-01
相关资源
最近更新 更多