diff options
author | Christopher Vogt <oss.nsp@cvogt.org> | 2016-03-06 23:35:57 -0500 |
---|---|---|
committer | Christopher Vogt <oss.nsp@cvogt.org> | 2016-03-06 23:35:57 -0500 |
commit | f0dc760df8757caea1d83b15142a3d0704488636 (patch) | |
tree | a3c9d8351de510d98610910862f91d8826b33ce1 /stage1/Stage1Lib.scala | |
parent | 4dae0e69f4b2947942d5ff7d4edee482073ee26b (diff) | |
download | cbt-f0dc760df8757caea1d83b15142a3d0704488636.tar.gz cbt-f0dc760df8757caea1d83b15142a3d0704488636.tar.bz2 cbt-f0dc760df8757caea1d83b15142a3d0704488636.zip |
trap and pass exit codes throug the app, pass logger on to tests, remove the lib. qualification from Stage1 for better readability
Diffstat (limited to 'stage1/Stage1Lib.scala')
-rw-r--r-- | stage1/Stage1Lib.scala | 106 |
1 files changed, 83 insertions, 23 deletions
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index e1b9d3d..ac77a92 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -3,6 +3,7 @@ package cbt import cbt.paths._ import java.io._ +import java.lang.reflect.InvocationTargetException import java.net._ import java.nio.file._ import javax.tools._ @@ -12,6 +13,24 @@ import javax.xml.bind.annotation.adapters.HexBinaryAdapter import scala.collection.immutable.Seq +// CLI interop +case class ExitCode(code: Int) +object ExitCode{ + val Success = ExitCode(0) + val Failure = ExitCode(1) +} + +class TrappedExitCode(private val exitCode: Int) extends Exception +object TrappedExitCode{ + def unapply(e: Throwable): Option[ExitCode] = + Option(e) flatMap { + case i: InvocationTargetException => unapply(i.getTargetException) + case e: TrappedExitCode => Some( ExitCode(e.exitCode) ) + case _ => None + } +} + + case class Context( cwd: String, args: Seq[String], logger: Logger ) case class ClassPath(files: Seq[File]){ @@ -97,16 +116,20 @@ class Stage1Lib( val logger: Logger ){ // ========== compilation / execution ========== - def runMainIfFound(cls: String, args: Seq[String], classLoader: ClassLoader ){ - if( classLoader.canLoad(cls) ) runMain(cls: String, args: Seq[String], classLoader: ClassLoader ) + def runMainIfFound(cls: String, args: Seq[String], classLoader: ClassLoader ): ExitCode = { + if( classLoader.canLoad(cls) ){ + runMain(cls, args, classLoader ) + } else ExitCode.Success } - def runMain(cls: String, args: Seq[String], classLoader: ClassLoader ){ + def runMain(cls: String, args: Seq[String], classLoader: ClassLoader ): ExitCode = { logger.lib(s"Running $cls.main($args) with classLoader: "+classLoader) - classLoader - .loadClass(cls) - .getMethod( "main", scala.reflect.classTag[Array[String]].runtimeClass ) - .invoke( null, args.toArray.asInstanceOf[AnyRef] ); + trapExitCode{ + classLoader + .loadClass(cls) + .getMethod( "main", scala.reflect.classTag[Array[String]].runtimeClass ) + .invoke( null, args.toArray.asInstanceOf[AnyRef] ) + } } implicit class ClassLoaderExtensions(classLoader: ClassLoader){ @@ -116,7 +139,7 @@ class Stage1Lib( val logger: Logger ){ true } catch { case e: ClassNotFoundException => false - } + } } } @@ -152,25 +175,33 @@ class Stage1Lib( val logger: Logger ){ val scalaReflect = MavenDependency("org.scala-lang","scala-reflect",scalaVersion)(logger).jar val scalaCompiler = MavenDependency("org.scala-lang","scala-compiler",scalaVersion)(logger).jar - redirectOutToErr{ - lib.runMain( - "com.typesafe.zinc.Main", - Seq( - "-scala-compiler", scalaCompiler.toString, - "-scala-library", scalaLibrary.toString, - "-sbt-interface", sbtInterface.toString, - "-compiler-interface", compilerInterface.toString, - "-scala-extra", scalaReflect.toString, - "-cp", cp, - "-d", compileTarget.toString - ) ++ extraArgs.map("-S"+_) ++ files.map(_.toString), - zinc.classLoader - ) + val code = redirectOutToErr{ + trapExitCode{ + lib.runMain( + "com.typesafe.zinc.Main", + Seq( + "-scala-compiler", scalaCompiler.toString, + "-scala-library", scalaLibrary.toString, + "-sbt-interface", sbtInterface.toString, + "-compiler-interface", compilerInterface.toString, + "-scala-extra", scalaReflect.toString, + "-cp", cp, + "-d", compileTarget.toString + ) ++ extraArgs.map("-S"+_) ++ files.map(_.toString), + zinc.classLoader + ) + } + } + if(code != ExitCode.Success){ + // FIXME: zinc currently always returns exit code 0 + // hack that triggers recompilation next time. Nicer solution? + val now = System.currentTimeMillis() + files.foreach{_.setLastModified(now)} } } } - def redirectOutToErr[T](code: => T): Unit = { + def redirectOutToErr[T](code: => T): T = { val oldOut = System.out try{ System.setOut(System.err) @@ -180,5 +211,34 @@ class Stage1Lib( val logger: Logger ){ } } + def trapExitCode( code: => Unit ): ExitCode = { + val old: Option[SecurityManager] = Option(System.getSecurityManager()) + try{ + val securityManager = new SecurityManager{ + override def checkPermission( permission: Permission ) = { + /* + NOTE: is it actually ok, to just make these empty? + Calling .super leads to ClassNotFound exteption for a lambda. + Calling to the previous SecurityManager leads to a stack overflow + */ + } + override def checkPermission( permission: Permission, context: Any ) = { + /* Does this methods need to be overidden? */ + } + override def checkExit( status: Int ) = { + super.checkExit(status) + logger.lib(s"checkExit($status)") + throw new TrappedExitCode(status) + } + } + System.setSecurityManager( securityManager ) + code + ExitCode.Success + } catch { + case TrappedExitCode(exitCode) => exitCode + } finally { + System.setSecurityManager(old.getOrElse(null)) + } + } } |