diff options
author | Christopher Vogt <oss.nsp@cvogt.org> | 2016-03-30 23:39:14 -0400 |
---|---|---|
committer | Christopher Vogt <oss.nsp@cvogt.org> | 2016-03-30 23:39:14 -0400 |
commit | 57de43907e05d4cd3986e2994e0e3bff93e09b4e (patch) | |
tree | 9e07a28943ffe0d9c2ace7f06315d8034f1dd6f8 /stage1 | |
parent | 8a4578311e4d11c06bfb4fe04e5bf414b94d24e8 (diff) | |
download | cbt-57de43907e05d4cd3986e2994e0e3bff93e09b4e.tar.gz cbt-57de43907e05d4cd3986e2994e0e3bff93e09b4e.tar.bz2 cbt-57de43907e05d4cd3986e2994e0e3bff93e09b4e.zip |
Makes zinc usage smarter, so we do not need to call it when no files changed (and safe up to 0.1s for each call)
There still seem to be 2 bugs related to CBT development in the code. One if you simpy save a stage1 file unchanged and re-run cbt, it fails to call Stage2.run reflectively. Also in case of compile errors in stage1, a TrappedExitCode exception is thrown and not caught.
Diffstat (limited to 'stage1')
-rw-r--r-- | stage1/Stage1.scala | 24 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 39 | ||||
-rw-r--r-- | stage1/paths.scala | 1 | ||||
-rw-r--r-- | stage1/resolver.scala | 16 |
4 files changed, 46 insertions, 34 deletions
diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index 32da3ed..be933d2 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -68,17 +68,21 @@ object Stage1{ val classLoaderCache = new ClassLoaderCache(logger) - val stage2SourcesChanged = sourceFiles.exists(newerThan(_, changeIndicator)) - logger.stage1("before conditionally running zinc to recompile CBT") - if( stage2SourcesChanged ) { - val scalaXml = JavaDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,constants.scalaXmlVersion) - logger.stage1("cbt.lib has changed. Recompiling.") - zinc( true, sourceFiles, stage2Target, nailgunTarget +: stage1Target +: Dependencies(deps, scalaXml).classpath, classLoaderCache, Seq("-deprecation") )( zincVersion = "0.3.9", scalaVersion = constants.scalaVersion ) - } + val stage2SourcesChanged = lib.needsUpdate(sourceFiles, stage2StatusFile) + logger.stage1("Compiling stage2 if necessary") + val scalaXml = JavaDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,constants.scalaXmlVersion) + compile( + stage2SourcesChanged, + sourceFiles, stage2Target, stage2StatusFile, + nailgunTarget +: stage1Target +: Dependencies(deps, scalaXml).classpath, + Seq("-deprecation"), classLoaderCache, + zincVersion = "0.3.9", scalaVersion = constants.scalaVersion + ) + logger.stage1(s"[$now] calling CbtDependency.classLoader") - val cl = classLoaderCache.transient.get( - (stage2Target +: deps.classpath).string, + val cl = /*classLoaderCache.transient.get( + (stage2Target +: deps.classpath).string,*/ cbt.URLClassLoader( ClassPath(Seq(stage2Target)), classLoaderCache.persistent.get( @@ -86,7 +90,7 @@ object Stage1{ cbt.URLClassLoader( deps.classpath, classLoader ) ) ) - ) + //) logger.stage1(s"[$now] Run Stage2") val exitCode = ( diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 69b828b..e4fe15e 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -6,6 +6,7 @@ import java.io._ import java.lang.reflect.InvocationTargetException import java.net._ import java.nio.file._ +import java.nio.file.attribute.FileTime import javax.tools._ import java.security._ import java.util._ @@ -111,14 +112,22 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ } } - def zinc( + def needsUpdate( sourceFiles: Seq[File], statusFile: File ) = { + val lastCompile = statusFile.lastModified + sourceFiles.filter(_.lastModified > lastCompile).nonEmpty + } + + def compile( needsRecompile: Boolean, files: Seq[File], compileTarget: File, + statusFile: File, classpath: ClassPath, + scalacOptions: Seq[String] = Seq(), classLoaderCache: ClassLoaderCache, - extraArgs: Seq[String] = Seq() - )( zincVersion: String, scalaVersion: String ): Unit = { + zincVersion: String, + scalaVersion: String + ): File = { val cp = classpath.string if(classpath.files.isEmpty) @@ -126,9 +135,6 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ if(files.isEmpty) throw new Exception("Trying to compile no files. ClassPath: " ++ cp) - - // only run zinc if files changed, for performance reasons - // FIXME: this is broken, need invalidate on changes in dependencies as well if( needsRecompile ){ val zinc = JavaDependency("com.typesafe.zinc","zinc", zincVersion) val zincDeps = zinc.transitiveDependencies @@ -151,6 +157,8 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ val scalaReflect = JavaDependency("org.scala-lang","scala-reflect",scalaVersion).jar val scalaCompiler = JavaDependency("org.scala-lang","scala-compiler",scalaVersion).jar + val start = System.currentTimeMillis + val code = redirectOutToErr{ lib.runMain( "com.typesafe.zinc.Main", @@ -162,22 +170,21 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ "-scala-extra", scalaReflect.toString, "-cp", cp, "-d", compileTarget.toString - ) ++ extraArgs.map("-S"++_) ++ files.map(_.toString), + ) ++ scalacOptions.map("-S"++_) ++ files.map(_.toString), zinc.classLoader(classLoaderCache) ) } - if(code != ExitCode.Success){ - // Ensure we trigger recompilation next time. This is currently required because we - // don't record the time of the last successful build elsewhere. But hopefully that will - // change soon. - val now = System.currentTimeMillis() - files.foreach(_.setLastModified(now)) - - // Tell the caller that things went wrong. - System.exit(code.integer) + if(code == ExitCode.Success){ + // write version and when last compilation started so we can trigger + // recompile if cbt version changed or newer source files are seen + Files.write(statusFile.toPath, "".getBytes)//cbtVersion.getBytes) + Files.setLastModifiedTime(statusFile.toPath, FileTime.fromMillis(start) ) + } else { + System.exit(code.integer) // FIXME: let's find a better solution for error handling. Maybe a monad after all. } } + compileTarget } def redirectOutToErr[T](code: => T): T = { val oldOut = System.out diff --git a/stage1/paths.scala b/stage1/paths.scala index e8e3cc5..f27e538 100644 --- a/stage1/paths.scala +++ b/stage1/paths.scala @@ -11,6 +11,7 @@ object paths{ private val target = Option(System.getenv("TARGET")).get.stripSuffix("/") val stage1Target: File = stage1 ++ ("/" ++ target) val stage2Target: File = stage2 ++ ("/" ++ target) + val stage2StatusFile: File = stage2Target ++ ".last-success" val nailgunTarget: File = nailgun ++ ("/" ++ target) val sonatypeLogin: File = cbtHome ++ "/sonatype.login" } diff --git a/stage1/resolver.scala b/stage1/resolver.scala index b8e6544..1dd4d6c 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -28,7 +28,7 @@ abstract class Dependency{ implicit def logger: Logger protected def lib = new Stage1Lib(logger) - def updated: Boolean + def needsUpdate: Boolean //def cacheClassLoader: Boolean = false private[cbt] def targetClasspath: ClassPath def exportedClasspath: ClassPath @@ -174,7 +174,7 @@ abstract class Dependency{ def dependencyTree: String = dependencyTreeRecursion() private def dependencyTreeRecursion(indent: Int = 0): String = ( ( " " * indent ) - ++ (if(updated) lib.red(show) else show) + ++ (if(needsUpdate) lib.red(show) else show) ++ dependencies.map( "\n" ++ _.dependencyTreeRecursion(indent + 1) ).mkString @@ -187,7 +187,7 @@ class ScalaLibraryDependency (version: String)(implicit logger: Logger) extends class ScalaReflectDependency (version: String)(implicit logger: Logger) extends JavaDependency("org.scala-lang","scala-reflect",version) case class ScalaDependencies(version: String)(implicit val logger: Logger) extends Dependency{ sd => - final val updated = false + override final val needsUpdate = false override def canBeCached = true def targetClasspath = ClassPath(Seq()) def exportedClasspath = ClassPath(Seq()) @@ -200,23 +200,23 @@ case class ScalaDependencies(version: String)(implicit val logger: Logger) exten } case class BinaryDependency( path: File, dependencies: Seq[Dependency] )(implicit val logger: Logger) extends Dependency{ - def updated = false def exportedClasspath = ClassPath(Seq(path)) def exportedJars = Seq[File](path) + override def needsUpdate = false def targetClasspath = exportedClasspath } /** Allows to easily assemble a bunch of dependencies */ case class Dependencies( _dependencies: Dependency* )(implicit val logger: Logger) extends Dependency{ override def dependencies = _dependencies.to - def updated = dependencies.exists(_.updated) + def needsUpdate = dependencies.exists(_.needsUpdate) def exportedClasspath = ClassPath(Seq()) def exportedJars = Seq() def targetClasspath = ClassPath(Seq()) } case class Stage1Dependency()(implicit val logger: Logger) extends Dependency{ - def updated = false // FIXME: think this through, might allow simplifications and/or optimizations + def needsUpdate = false // FIXME: think this through, might allow simplifications and/or optimizations override def canBeCached = false /* private object classLoaderRecursionCache extends Cache[ClassLoader] @@ -245,7 +245,7 @@ case class CbtDependency()(implicit val logger: Logger) extends Dependency{ "org.scala-lang.modules","scala-xml","1.0.5", scalaVersion = constants.scalaMajorVersion ) ) - def updated = false // FIXME: think this through, might allow simplifications and/or optimizations + def needsUpdate = false // FIXME: think this through, might allow simplifications and/or optimizations def targetClasspath = exportedClasspath } @@ -260,7 +260,7 @@ case class JavaDependency( groupId: String, artifactId: String, version: String, classifier: Classifier = Classifier.none )(implicit val logger: Logger) extends ArtifactInfo{ - def updated = false + override def needsUpdate = false override def canBeCached = true private val groupPath = groupId.split("\\.").mkString("/") |