Код выхода для проекта sbt

У меня есть проект, построенный с помощью sbt и актеров akka. Я запускаю его с помощью команды «sbt 'run $args'» и хочу, чтобы эта программа возвращала разные коды выхода в зависимости от некоторых условий. Для этих целей я использую System.exit(code) от моего главного актера.
Проблема, которую я не могу решить, заключается в том, что код выхода sbt зависит от аргументов программы: иногда он завершается с ошибкой.

java.lang.RuntimeException: Nonzero exit code returned from runner: 3        at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:runMain for the full output.
[error] (compile:runMain) Nonzero exit code returned from runner: 3
[error] Total time: 5 s, completed Dec 4, 2014 6:50:50 PM

это не красота, но это нормально.
Но в некоторых случаях я запускаю System.exit(3), но sbt завершается с кодом выхода 0 и сообщением [success].
Есть способ заставить sbt выйти с тем же кодом, что и моя программа?
P.S. Я не уверен, но похоже, что основное различие между аргументами заключается в том, что в первом случае программа выполняется в одном потоке, а во втором случае она выполняется в более чем 1 потоке.


person Dmitry Meshkov    schedule 04.12.2014    source источник


Ответы (1)


System.exit (или лучше: sys.exit) закрывает текущую среду выполнения. Если sbt разветвляет среду выполнения, то вызов sys.exit завершает работу не самого sbt, а только разветвленного процесса. Например, если у вас есть fork in Run := true, то вызов sbt run заставит sbt создать вторую независимую JVM (разумеется, вы не хотите возиться с той же JVM).

В таких случаях вы можете определить пользовательскую задачу запуска, которая повторяет sys.exit для фактического экземпляра sbt.


Изменить. Вот минимальный пример:

// project/build.properties
sbt.version = 0.13.6

// build.sbt
scalaVersion := "2.11.4"

lazy val myRun = taskKey[Unit]("A custom run task.")

fork in myRun := true

myRun := {
  val r   = (runner in Compile).value
  val cp  = (fullClasspath in Compile).value
  val res = r.run("foo.Bar", cp.map(_.data), Nil, streams.value.log)
  val ExitCode = "Nonzero exit code: (-?\\d+)".r
  val code = res match {
    case Some(ExitCode(c)) => c.toInt
    case _ => 0
  }
  println(s"myRun returned with $code")
  if (code != 0) sys.exit(code)
}

// src/main/scala/foo/Bar.scala 
package foo

object Bar extends App {
  println("Hello.")
  sys.exit(3)
}

Для проверки: sbt myRun. Не спрашивайте меня, почему run возвращает Option[String] вместо прямого Int.

person 0__    schedule 04.12.2014
comment
Спасибо за ваш ответ, но я получаю сообщение об ошибке с этим решением: ошибка: значение символа ExitCode не существует в $b001ceba8a6ab7cd4585.$sbtdef scala.reflect.internal.FatalError: - person Dmitry Meshkov; 05.12.2014
comment
sbt использует собственную версию Scala, независимую от вашего проекта, так что это не имеет значения. Вероятно, вы не используете sbt 0.13. Вы видели первые несколько строк, указывающих версию sbt в project/build.properties? Я думаю, что более старые версии sbt используют Scala 2.9, в котором нет метода регулярных выражений, который я использую для ExitCode. - person 0__; 05.12.2014