2

我在build.sbt脚本中有一个函数可以自动检测 OS X 上的最新 Java 运行时。这很好用,直到一些不再喜欢它的更新(sbt 或 Scala)。我什至不能做sbt clean但得到一个错误(下)。

该功能是(只需将其粘贴到您的build.sbt并运行sbt clean就足以测试它 - 代码不需要执行):

javaHome := {
  var s = System.getenv("JAVA_HOME")
  if (s==null) {
    // Try to detect the latest JDK
    //
    // OS X: "/Library/Java/JavaVirtualMachines/jdk1.xxx.jdk/Contents/Home" with greatest id (i.e. "7.0_11")
    // Linux: tbd
    // Windows: tbd
    //
    val base= new File("/Library/Java/JavaVirtualMachines")
    assert( base.isDirectory, "Java JDKs not found at: "+ base )
    //
    // Get the latest version number available
    //
    // Note: JDK 7 has i.e. "jdk1.7.0_11.jdk"
    //       JDK 8 (early access) has "jdk1.8.0.jdk" (no underscore)
    //
    // For re explanation, see: http://stackoverflow.com/questions/8213837/optional-grouping-in-scala-regular-expressions
    // Triple quotes """ means '\' does not need to be escaped.
    //
    val re = """^jdk(\d+)\.(\d+)\.(\d+)(?:_([\d]*))?\.jdk$""".r
    var best = 0  // latest version so far
    base.listFiles.filter(_.isDirectory).map( (f: File) => {    // 'dir.name' i.e. "jdk1.7.0_11.jdk", "jdk1.8.0.jdk"
      try {
        val re(a,b,c,d) = f.name    // unapplies the caught parts
        val abcd= (((a.toInt)*100 + b.toInt)*100 + c.toInt)*100 + (Option(d) getOrElse "0").toInt
        println( "Found JVM: ", a, b, c, d )
        if (b=="8") {
          throw new RuntimeException( "Cannot use JavaFX 8 due to ScalaFX: please set 'JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.xxx.jdk/Contents/Home' env.var." )
        } else if (abcd>best) {
          best= abcd
          s= base+"/"+f.name+"/Contents/Home/"   // postfix in OS X
        }
      } catch { 
        // not really supposed to be having non-matching directories there (just skip them)
        case e: MatchError => None
      }
    } )
    //
    if (s==null) {
      throw new RuntimeException( "No JDK found at: "+ base )
    }
  }
  //
  println( "*** Using Java JDK: "+ s )
  val dir = new File(s)
  if (!dir.isDirectory) {
    throw new RuntimeException( "No JDK found at: "+ s )
  }
  //
  Some(dir)  // 'sbt' 'javaHome' value is ': Option[java.io.File]'
}

我得到的是:

$ sbt clean
[info] Loading project definition from /Users/asko/Hg/ScalaSim/project
**error: symbol value re does not exist in $cdeec6b653504a14ad9f.$sbtdef**
[error] scala.reflect.internal.FatalError: 
[error]      while compiling: /Users/asko/Hg/ScalaSim/build.sbt
[error]         during phase: icode
[error]      library version: version 2.10.2
[error]     compiler version: version 2.10.2
[error]   reconstructed args: -classpath /Users/asko/Hg/ScalaSim/project/target/scala-2.10/sbt-0.13/classes:/Users/asko/.ivy2/cache/scala_2.10/sbt_0.13/com.github.retronym/sbt-onejar/jars/sbt-onejar-0.8.jar:/Users/asko/.ivy2/cache/scala_2.10/sbt_0.13/com.eed3si9n/sbt-assembly/jars/sbt-assembly-0.9.1.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/actions-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/api-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/apply-macro-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/cache-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/classfile-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/classpath-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/collections-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/command-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/compile-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/compiler-integration-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/compiler-ivy-integration-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/completion-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/control-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/cross-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/incremental-compiler-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/io-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/ivy-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/ivy-2.3.0-rc1.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/jline-2.11.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/jsch-0.1.46.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/launcher-interface-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/logging-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/main-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/main-settings-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/persist-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/process-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/relation-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/run-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/sbinary_2.10-0.4.2.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/sbt-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/scala-reflect-2.10.2.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/task-system-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/tasks-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/test-agent-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/test-interface-1.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/testing-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/tracking-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/org.scala-sbt/sbt/0.13.0/xsbti/interface-0.13.0.jar:/Users/asko/.sbt/boot/scala-2.10.2/lib/jansi.jar:/Users/asko/.sbt/boot/scala-2.10.2/lib/jline.jar:/Users/asko/.sbt/boot/scala-2.10.2/lib/scala-compiler.jar:/Users/asko/.sbt/boot/scala-2.10.2/lib/scala-library.jar:/Users/asko/.sbt/boot/scala-2.10.2/lib/scala-reflect.jar:/Users/asko/Hg/ScalaSim/project/target/config-classes
[error] 
[error]   last tree to typer: Ident(re$1)
[error]               symbol: value re$1 (flags: <param> <synthetic> <triedcooking>)
[error]    symbol definition: re$1: util.matching.Regex
[error]                  tpe: util.matching.Regex
[error]        symbol owners: value re$1 -> constructor $cdeec6b653504a14ad9f$$anonfun$$sbtdef$1 -> anonymous class sbtdef$1 -> package <empty>
[error]       context owners: anonymous class sbtdef$1 -> package <empty>
[error] 
[error] == Enclosing template or block ==
[error] 
...
[error] 
[error] == Expanded type of tree ==
[error] 
[error] TypeRef(TypeSymbol(class Regex extends Serializable))
[error] 
[error] symbol value re does not exist in $cdeec6b653504a14ad9f.$sbtdef
[error] Use 'last' for the full log.
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? 

谁能告诉我这里发生了什么?是我还是sbt?

4

2 回答 2

2

我认为 sbt 0.13 的宏处理(或一般宏)存在错误。拿出val re来,它工作正常:

val re = """^jdk(\d+)\.(\d+)\.(\d+)(?:_([\d]*))?\.jdk$""".r

javaHome := {
  var s = System.getenv("JAVA_HOME")
  if (s==null) {
    // Try to detect the latest JDK
    //
    // OS X: "/Library/Java/JavaVirtualMachines/jdk1.xxx.jdk/Contents/Home" with greatest id (i.e. "7.0_11")
    // Linux: tbd
    // Windows: tbd
    //
    val base= new File("/Library/Java/JavaVirtualMachines")
    assert( base.isDirectory, "Java JDKs not found at: "+ base )
    //
    // Get the latest version number available
    //
    // Note: JDK 7 has i.e. "jdk1.7.0_11.jdk"
    //       JDK 8 (early access) has "jdk1.8.0.jdk" (no underscore)
    //
    // For re explanation, see: http://stackoverflow.com/questions/8213837/optional-grouping-in-scala-regular-expressions
    // Triple quotes """ means '\' does not need to be escaped.
    //
    var best = 0  // latest version so far
    base.listFiles.filter(_.isDirectory).map( (f: File) => {    // 'dir.name' i.e. "jdk1.7.0_11.jdk", "jdk1.8.0.jdk"
      try {
        val re(a,b,c,d) = f.name    // unapplies the caught parts
        val abcd= (((a.toInt)*100 + b.toInt)*100 + c.toInt)*100 + (Option(d) getOrElse "0").toInt
        println( "Found JVM: ", a, b, c, d )
        if (b=="8") {
          throw new RuntimeException( "Cannot use JavaFX 8 due to ScalaFX: please set 'JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.xxx.jdk/Contents/Home' env.var." )
        } else if (abcd>best) {
          best= abcd
          s= base+"/"+f.name+"/Contents/Home/"   // postfix in OS X
        }
      } catch { 
        // not really supposed to be having non-matching directories there (just skip them)
        case e: MatchError => None
      }
    } )
    //
    if (s==null) {
      throw new RuntimeException( "No JDK found at: "+ base )
    }
  }
  //
  println( "*** Using Java JDK: "+ s )
  val dir = new File(s)
  if (!dir.isDirectory) {
    throw new RuntimeException( "No JDK found at: "+ s )
  }
  //
  Some(dir)  // 'sbt' 'javaHome' value is ': Option[java.io.File]'
}

这是我得到的:

*** Using Java JDK: /Library/Java/Home/
于 2013-09-23T16:51:01.487 回答
1

它是 sbt。

很有意思!SBT 0.13 开始使用宏,因此它可以简化声明,但您偶然发现了一些因此而停止工作的东西。请将此报告为 SBT 上的错误。

于 2013-09-23T16:49:58.990 回答