Create RunFromSourceMain & "sbtOn" command

This commit is contained in:
Dale Wijnand 2017-11-23 14:58:26 +00:00
parent 5b0b9e2ba2
commit 9c32c16ade
No known key found for this signature in database
GPG Key ID: 4F256E3D151DF5EF
3 changed files with 120 additions and 0 deletions

View File

@ -376,17 +376,26 @@ lazy val mainProj = (project in file("main"))
// with the sole purpose of providing certain identifiers without qualification (with a package object)
lazy val sbtProj = (project in file("sbt"))
.dependsOn(mainProj, scriptedSbtProj % "test->test")
.enablePlugins(BuildInfoPlugin)
.settings(
baseSettings,
name := "sbt",
normalizedName := "sbt",
crossScalaVersions := Seq(baseScalaVersion),
crossPaths := false,
javaOptions ++= Seq("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"),
mimaSettings,
mimaBinaryIssueFilters ++= sbtIgnoredProblems,
addBuildInfoToConfig(Test),
buildInfoObject in Test := "TestBuildInfo",
buildInfoKeys in Test := Seq[BuildInfoKey](fullClasspath in Compile),
connectInput in run in Test := true,
)
.configure(addSbtCompilerBridge)
commands in Global += Command.single("sbtOn")((state, dir) =>
s"sbtProj/test:runMain sbt.RunFromSourceMain $dir" :: state)
lazy val sbtIgnoredProblems = {
Seq(
// Added more items to Import trait.

View File

@ -11,3 +11,4 @@ addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0-M1")
addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.10")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")

View File

@ -0,0 +1,110 @@
package sbt
import scala.annotation.tailrec
import xsbti._
object RunFromSourceMain {
private val sbtVersion = "1.0.3" // "dev"
private val scalaVersion = "2.12.4"
def main(args: Array[String]): Unit = args match {
case Array() => sys.error(s"Must specify working directory as the first argument")
case Array(wd, args @ _*) => run(file(wd), args)
}
// this arrangement is because Scala does not always properly optimize away
// the tail recursion in a catch statement
@tailrec private def run(baseDir: File, args: Seq[String]): Unit =
runImpl(baseDir, args) match {
case Some((baseDir, args)) => run(baseDir, args)
case None => ()
}
private def runImpl(baseDir: File, args: Seq[String]): Option[(File, Seq[String])] =
try launch(getConf(baseDir, args)) map exit
catch {
case r: xsbti.FullReload => Some((baseDir, r.arguments()))
case scala.util.control.NonFatal(e) => e.printStackTrace(); errorAndExit(e.toString)
}
@tailrec private def launch(conf: AppConfiguration): Option[Int] =
new xMain().run(conf) match {
case e: xsbti.Exit => Some(e.code)
case _: xsbti.Continue => None
case r: xsbti.Reboot => launch(getConf(conf.baseDirectory(), r.arguments()))
case x => handleUnknownMainResult(x)
}
private val noGlobalLock = new GlobalLock {
def apply[T](lockFile: File, run: java.util.concurrent.Callable[T]) = run.call()
}
private def getConf(baseDir: File, args: Seq[String]): AppConfiguration = new AppConfiguration {
def baseDirectory = baseDir
def arguments = args.toArray
def provider = new AppProvider { appProvider =>
def scalaProvider = new ScalaProvider { scalaProvider =>
def scalaOrg = "org.scala-lang"
def launcher = new Launcher {
def getScala(version: String) = getScala(version, "")
def getScala(version: String, reason: String) = getScala(version, reason, scalaOrg)
def getScala(version: String, reason: String, scalaOrg: String) = scalaProvider
def app(id: xsbti.ApplicationID, version: String) = appProvider
def topLoader = new java.net.URLClassLoader(Array(), null)
def globalLock = noGlobalLock
def bootDirectory = file(sys.props("user.home")) / ".sbt" / "boot"
def ivyRepositories = Array()
def appRepositories = Array()
def isOverrideRepositories = false
def ivyHome = file(sys.props("user.home")) / ".ivy2"
def checksums = Array("sha1", "md5")
}
def version = scalaVersion
def libDir: File = launcher.bootDirectory / s"scala-$version" / "lib"
def jar(name: String): File = libDir / s"$name.jar"
def libraryJar = jar("scala-library")
def compilerJar = jar("scala-compiler")
def jars = libDir.listFiles(f => !f.isDirectory && f.getName.endsWith(".jar"))
def loader = new java.net.URLClassLoader(jars map (_.toURI.toURL), null)
def app(id: xsbti.ApplicationID) = appProvider
}
def id = ApplicationID(
"org.scala-sbt",
"sbt",
sbtVersion,
"sbt.xMain",
Seq("xsbti", "extra"),
CrossValue.Disabled,
Nil
)
def mainClasspath =
buildinfo.TestBuildInfo.fullClasspath.iterator
.map(s => file(s.stripPrefix("Attributed(").stripSuffix(")")))
.toArray
def loader = new java.net.URLClassLoader(mainClasspath map (_.toURI.toURL), null)
def entryPoint = classOf[xMain]
def mainClass = classOf[xMain]
def newMain = new xMain
def components = new ComponentProvider {
def componentLocation(id: String) = ???
def component(componentID: String) = ???
def defineComponent(componentID: String, components: Array[File]) = ???
def addToComponent(componentID: String, components: Array[File]) = ???
def lockFile = ???
}
}
}
private def handleUnknownMainResult(x: MainResult): Nothing = {
val clazz = if (x eq null) "" else " (class: " + x.getClass + ")"
errorAndExit("Invalid main result: " + x + clazz)
}
private def errorAndExit(msg: String): Nothing = { System.err.println(msg); exit(1) }
private def exit(code: Int): Nothing = System.exit(code).asInstanceOf[Nothing]
}