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 | |
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')
-rw-r--r-- | stage1/Stage1.scala | 26 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 106 | ||||
-rw-r--r-- | stage1/logger.scala | 2 |
3 files changed, 98 insertions, 36 deletions
diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index 5391e2d..8db12cf 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -14,7 +14,7 @@ object CheckAlive{ } } -private[cbt] class Init(args: Array[String]) { +class Init(args: Array[String]) { /** * Raw parameters including their `-D` flag. **/ @@ -35,8 +35,6 @@ private[cbt] class Init(args: Array[String]) { }).toMap ++ System.getProperties.asScala val logger = new Logger(props.get("log")) - - val cwd = argsV(0) } object Stage1 extends Stage1Base{ @@ -57,25 +55,27 @@ abstract class Stage1Base{ def main(args: Array[String]): Unit = { val init = new Init(args) val lib = new Stage1Lib(init.logger) + import lib._ - lib.logger.stage1(s"[$now] Stage1 start") - lib.logger.stage1("Stage1: after creating lib") + logger.stage1(s"[$now] Stage1 start") + logger.stage1("Stage1: after creating lib") val cwd = args(0) val src = stage2.listFiles.toVector.filter(_.isFile).filter(_.toString.endsWith(".scala")) val changeIndicator = new File(stage2Target+"/cbt/Build.class") - lib.logger.stage1("before conditionally running zinc to recompile CBT") + logger.stage1("before conditionally running zinc to recompile CBT") if( src.exists(newerThan(_, changeIndicator)) ) { - val stage1Classpath = CbtDependency(init.logger).dependencyClasspath - lib.logger.stage1("cbt.lib has changed. Recompiling with cp: "+stage1Classpath) - lib.zinc( true, src, stage2Target, stage1Classpath )( zincVersion = "0.3.9", scalaVersion = constants.scalaVersion ) + val stage1Classpath = CbtDependency(logger).dependencyClasspath + logger.stage1("cbt.lib has changed. Recompiling with cp: "+stage1Classpath) + zinc( true, src, stage2Target, stage1Classpath )( zincVersion = "0.3.9", scalaVersion = constants.scalaVersion ) } - lib.logger.stage1(s"[$now] calling CbtDependency.classLoader") + logger.stage1(s"[$now] calling CbtDependency.classLoader") - lib.logger.stage1(s"[$now] Run Stage2") - lib.runMain( mainClass, cwd +: args.drop(1).toVector, CbtDependency(init.logger).classLoader ) - lib.logger.stage1(s"[$now] Stage1 end") + logger.stage1(s"[$now] Run Stage2") + val ExitCode(exitCode) = runMain( mainClass, cwd +: args.drop(1).toVector, CbtDependency(logger).classLoader ) + logger.stage1(s"[$now] Stage1 end") + System.exit(exitCode) } } 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)) + } + } } diff --git a/stage1/logger.scala b/stage1/logger.scala index eaf64db..ecc1579 100644 --- a/stage1/logger.scala +++ b/stage1/logger.scala @@ -28,6 +28,7 @@ case class Logger(enabledLoggers: Set[String]) { final def composition(msg: => String) = logGuarded(names.composition, msg) final def resolver(msg: => String) = logGuarded(names.resolver, msg) final def lib(msg: => String) = logGuarded(names.lib, msg) + final def test(msg: => String) = logGuarded(names.test, msg) private object names{ val stage1 = "stage1" @@ -37,6 +38,7 @@ case class Logger(enabledLoggers: Set[String]) { val resolver = "resolver" val composition = "composition" val lib = "lib" + val test = "test" } private def logGuarded(name: String, msg: => String) = { |