Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.eed3si9n.jarjarabrams.ModuleCoordinate
// ThisBuild settings take lower precedence,
// but can be shared across the multi projects.
ThisBuild / version := {
val v = "2.0.0-RC4-bin-SNAPSHOT"
val v = "2.0.0-RC6-bin-SNAPSHOT"
nightlyVersion.getOrElse(v)
}
ThisBuild / Utils.version2_13 := "2.0.0-SNAPSHOT"
Expand Down Expand Up @@ -303,7 +303,10 @@ lazy val utilCore = project
utilCommonSettings,
name := "Util Core",
Utils.keywordsSettings,
mimaSettings
mimaSettings,
mimaBinaryIssueFilters ++= Seq(
exclude[DirectMissingMethodProblem]("sbt.internal.util.Util.majorJavaVersion"),
),
)

lazy val utilLogging = project
Expand Down
25 changes: 6 additions & 19 deletions internal/util-core/src/main/scala/sbt/internal/util/Util.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import java.util.Locale

import scala.collection.concurrent.TrieMap
import scala.reflect.Selectable.reflectiveSelectable
import scala.util.control.NonFatal
import scala.util.Properties

object Util:
def makeList[T](size: Int, value: T): List[T] = List.fill(size)(value)
Expand Down Expand Up @@ -96,17 +96,7 @@ object Util:
def reduceIntents[A1, A2](intents: PartialFunction[A1, A2]*): PartialFunction[A1, A2] =
intents.toList.reduceLeft(_ orElse _)

lazy val majorJavaVersion: Int =
try {
val javaVersion = sys.props.get("java.version").getOrElse("1.0")
if (javaVersion.startsWith("1.")) {
javaVersion.split("\\.")(1).toInt
} else {
javaVersion.split("\\.")(0).toInt
}
} catch {
case NonFatal(_) => 0
}
lazy val isJava19Plus: Boolean = Properties.isJavaAtLeast("19")

private type GetId = {
def getId: Long
Expand All @@ -121,13 +111,10 @@ object Util:
* https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Thread.html#threadId()
*/
def threadId: Long =
if (majorJavaVersion < 19) {
(Thread.currentThread(): AnyRef) match {
if !isJava19Plus then
(Thread.currentThread(): AnyRef) match
case g: GetId @unchecked => g.getId
}
} else {
(Thread.currentThread(): AnyRef) match {
else
(Thread.currentThread(): AnyRef) match
case g: ThreadId @unchecked => g.threadId
}
}
end Util
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object Dependencies {

// sbt modules
private val ioVersion = nightlyVersion.getOrElse("1.10.5")
val zincVersion = nightlyVersion.getOrElse("2.0.0-M8")
val zincVersion = nightlyVersion.getOrElse("2.0.0-M9")

private val sbtIO = "org.scala-sbt" %% "io" % ioVersion

Expand Down
61 changes: 46 additions & 15 deletions run/src/main/scala/sbt/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import sbt.util.Logger

import scala.sys.process.Process
import scala.util.control.NonFatal
import scala.util.{ Failure, Success, Try }
import scala.util.{ Failure, Properties, Success, Try }

sealed trait ScalaRun:
def run(mainClass: String, classpath: Seq[NioPath], options: Seq[String], log: Logger): Try[Unit]
Expand Down Expand Up @@ -93,7 +93,7 @@ class Run(private[sbt] val newLoader: Seq[NioPath] => ClassLoader, trapExit: Boo
def execute(): Unit =
try {
log.debug(" Classpath:\n\t" + classpath.mkString("\n\t"))
val main = getMainMethod(mainClass, loader)
val main = detectMainMethod(mainClass, loader)
invokeMain(loader, main, options)
} catch {
case e: java.lang.reflect.InvocationTargetException =>
Expand Down Expand Up @@ -141,14 +141,22 @@ class Run(private[sbt] val newLoader: Seq[NioPath] => ClassLoader, trapExit: Boo
}
private def invokeMain(
loader: ClassLoader,
main: Method,
main: DetectedMain,
options: Seq[String]
): Unit = {
val currentThread = Thread.currentThread
val oldLoader = Thread.currentThread.getContextClassLoader
currentThread.setContextClassLoader(loader)
try {
main.invoke(null, options.toArray[String]); ()
if (main.isStatic) {
if (main.parameterCount > 0) main.method.invoke(null, options.toArray[String])
else main.method.invoke(null)
} else {
val ref = main.mainClass.getDeclaredConstructor().newInstance().asInstanceOf[AnyRef]
if (main.parameterCount > 0) main.method.invoke(ref, options.toArray[String])
else main.method.invoke(ref)
}
()
} catch {
case t: Throwable =>
t.getCause match {
Expand All @@ -164,19 +172,40 @@ class Run(private[sbt] val newLoader: Seq[NioPath] => ClassLoader, trapExit: Boo
currentThread.setContextClassLoader(oldLoader)
}
}
def getMainMethod(mainClassName: String, loader: ClassLoader) = {
def getMainMethod(mainClassName: String, loader: ClassLoader): Method =
detectMainMethod(mainClassName, loader).method

private def detectMainMethod(mainClassName: String, loader: ClassLoader) = {
val mainClass = Class.forName(mainClassName, true, loader)
val method = mainClass.getMethod("main", classOf[Array[String]])
// jvm allows the actual main class to be non-public and to run a method in the non-public class,
// we need to make it accessible
method.setAccessible(true)
val modifiers = method.getModifiers
if (!isPublic(modifiers))
throw new NoSuchMethodException(mainClassName + ".main is not public")
if (!isStatic(modifiers))
throw new NoSuchMethodException(mainClassName + ".main is not static")
method
if (Run.isJava25Plus) {
val method =
try {
mainClass.getMethod("main", classOf[Array[String]])
} catch {
case _: NoSuchMethodException => mainClass.getMethod("main")
}
method.setAccessible(true)
val modifiers = method.getModifiers
DetectedMain(mainClass, method, isStatic(modifiers), method.getParameterCount())
} else {
val method = mainClass.getMethod("main", classOf[Array[String]])
// jvm allows the actual main class to be non-public and to run a method in the non-public class,
// we need to make it accessible
method.setAccessible(true)
val modifiers = method.getModifiers
if (!isPublic(modifiers))
throw new NoSuchMethodException(mainClassName + ".main is not public")
if (!isStatic(modifiers))
throw new NoSuchMethodException(mainClassName + ".main is not static")
DetectedMain(mainClass, method, isStatic = true, method.getParameterCount())
}
}
private case class DetectedMain(
mainClass: Class[?],
method: Method,
isStatic: Boolean,
parameterCount: Int
)
}

/** This module is an interface to starting the scala interpreter or runner. */
Expand Down Expand Up @@ -207,4 +236,6 @@ object Run:
s"""nonzero exit code returned from $label: $exitCode""".stripMargin
)
)

private[sbt] lazy val isJava25Plus: Boolean = Properties.isJavaAtLeast("25")
end Run

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

7 changes: 7 additions & 0 deletions sbt-app/src/sbt-test/run/jep-512/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package example

class A {
def main(): Unit = {
println("hi")
}
}
13 changes: 13 additions & 0 deletions sbt-app/src/sbt-test/run/jep-512/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 2.12.x uses Zinc's compiler bridge
ThisBuild / scalaVersion := "2.12.20"

@transient
lazy val check = taskKey[Unit]("")

Compile / run / fork := false

check := {
if (scala.util.Properties.isJavaAtLeast("25"))
(Compile / fgRun).toTask(" ").value
else ()
}
2 changes: 2 additions & 0 deletions sbt-app/src/sbt-test/run/jep-512/pending
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# > run
> check
Loading