aboutsummaryrefslogtreecommitdiff
path: root/stage1
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2016-03-30 23:39:14 -0400
committerChristopher Vogt <oss.nsp@cvogt.org>2016-03-30 23:39:14 -0400
commit57de43907e05d4cd3986e2994e0e3bff93e09b4e (patch)
tree9e07a28943ffe0d9c2ace7f06315d8034f1dd6f8 /stage1
parent8a4578311e4d11c06bfb4fe04e5bf414b94d24e8 (diff)
downloadcbt-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.scala24
-rw-r--r--stage1/Stage1Lib.scala39
-rw-r--r--stage1/paths.scala1
-rw-r--r--stage1/resolver.scala16
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("/")