如何在自定义sbt命令中设置javaOptions

时间:2019-02-03 13:44:57

标签: scala sbt

我正在尝试向SBT添加自定义命令(当前使用1.2.8版),以使用不同的javaOptions启动我的应用程序。我设法创建了3个单独的任务来为三种启动可能性完成此任务,但现在我想对此进行概括以允许使用任何启动参数。 到目前为止,我已经成功创建了以下build.sbt,但控制台输出显示sbt runNode node3仍然使用第13行(run / javaOptions ++= Seq(...)上设置的原始类路径。 显然,第46行上的run / javaOptions += s"-Djava.library.path=./target/native/$arg"被忽略了。

import com.typesafe.sbt.SbtMultiJvm.multiJvmSettings
import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys.MultiJvm
import Dependencies._

lazy val `akka-crdt-features` = project
  .in(file("."))
  .settings(multiJvmSettings: _*)
  .settings(
    organization := "nl.about42.akkamavericks",
    scalaVersion := "2.12.8",
    Compile / scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlog-reflective-calls", "-Xlint"),
    Compile / javacOptions ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"),
    run / javaOptions ++= Seq("-Xms128m", "-Xmx1024m", "-Djava.library.path=./target/native"),
    //run / javaOptions ++= Seq("-agentlib:hprof=heap=dump,format=b"),
    libraryDependencies ++= akkaDependencies ++ otherDependencies,
    run / fork := true,
    Compile / run / mainClass := Some("nl.about42.akkamavericks.cluster.ClusterCrdtApp"),
    // disable parallel tests
    Test / parallelExecution := false,
    licenses := Seq(("CC BY 4.0", url("https://creativecommons.org/licenses/by/4.0/"))),
    commands ++= Seq(runNodeCommand),
    Global / cancelable := true
  )
  .configs (MultiJvm)

// setup commands to run each individual node, using a separate folder for the extracted libsigar
lazy val runNode1 = taskKey[Unit]("Run node 1")
lazy val runNode2 = taskKey[Unit]("Run node 2")
lazy val runNode3 = taskKey[Unit]("Run node 3")

runNode1 / fork := true
runNode2 / fork := true
runNode3 / fork := true

runNode1 / javaOptions += "-Djava.library.path=./target/native/node1"
runNode2 / javaOptions += "-Djava.library.path=./target/native/node2"
runNode3 / javaOptions += "-Djava.library.path=./target/native/node3"

fullRunTask(runNode1, Compile, "nl.about42.akkamavericks.cluster.ClusterCrdtApp", "node1")
fullRunTask(runNode2, Compile, "nl.about42.akkamavericks.cluster.ClusterCrdtApp", "node2")
fullRunTask(runNode3, Compile, "nl.about42.akkamavericks.cluster.ClusterCrdtApp", "node3")

// setup command to start a single node, using separate folder for the extracted libsigar
// assumes sane node names that can be used as folder names
val runNodeAction: (State, String) => State = { (state, arg) =>
  run / javaOptions += s"-Djava.library.path=./target/native/$arg"
  val runCommand: Exec = Exec.apply(s"run $arg", state.source)
  state.copy(
    remainingCommands = runCommand +: state.remainingCommands
  )
}

val runNodeCommand: Command = Command.single("runNode")(runNodeAction)

sbt runNode node3的输出显示(相关行):

[error] no libsigar-amd64-linux.so in java.library.path: [./target/native]
[error] org.hyperic.sigar.SigarException: no libsigar-amd64-linux.so in java.library.path: [./target/native]

我希望它提到./target/native/node3

我的目标是仅使用sbt命令定义,因此我可以调用runNode [anyNodeName]并让SBT使用适当的类路径设置和启动参数来启动我的应用程序。

更新: 我在以下方面取得了部分成功:

val runNodeAction: (State, String) => State = { (state, arg) =>
  val stateWithNewOptions = Project.extract(state).appendWithSession(
    Seq(
      run / javaOptions += s"-Djava.library.path=./target/native/$arg"
    ),
    state
  )
  val runCommand: Exec = Exec.apply(s"run $arg", stateWithNewOptions.source)
  stateWithNewOptions.copy(
    remainingCommands = runCommand +: state.remainingCommands
  )
}

但是,这会将类路径设置为最新运行(不会恢复为默认值)。

1 个答案:

答案 0 :(得分:2)

在回答https://stackoverflow.com/a/54488121/2037054的马里奥·加里奇(Conditional scalacSettings / settingKey)的帮助下,我设法使它工作:

// setup command to start a single node, using separate folder for the extracted libsigar
// assumes sane node names that can be used as folder names
val runNodeAction: (State, String) => State = { (state, arg) =>
  val stateWithNewOptions = Project.extract(state).appendWithSession(
    Seq(
      run / javaOptions += s"-Djava.library.path=./target/native/$arg"
    ),
    state
  )
  val (s, _) = Project.extract(stateWithNewOptions).runInputTask(Compile / run, s" $arg", stateWithNewOptions)
  s
}

val runNodeCommand: Command = Command.single("runNode")(runNodeAction)