diff options
-rw-r--r-- | compatibility/Dependency.java | 1 | ||||
-rw-r--r-- | plugins/essentials/DynamicOverrides.scala | 10 | ||||
-rw-r--r-- | plugins/scalajs/ScalaJsLib.scala | 2 | ||||
-rw-r--r-- | stage1/Cache.scala | 14 | ||||
-rw-r--r-- | stage1/ContextImplementation.scala | 32 | ||||
-rw-r--r-- | stage1/MavenRepository.scala | 10 | ||||
-rw-r--r-- | stage1/Stage1.scala | 15 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 25 | ||||
-rw-r--r-- | stage1/cbt.scala | 4 | ||||
-rw-r--r-- | stage1/logger.scala | 2 | ||||
-rw-r--r-- | stage1/resolver.scala | 102 | ||||
-rw-r--r-- | stage2/BasicBuild.scala | 29 | ||||
-rw-r--r-- | stage2/BuildBuild.scala | 3 | ||||
-rw-r--r-- | stage2/BuildDependency.scala | 3 | ||||
-rw-r--r-- | stage2/GitDependency.scala | 10 | ||||
-rw-r--r-- | stage2/Lib.scala | 4 | ||||
-rw-r--r-- | stage2/PackageJars.scala | 9 | ||||
-rw-r--r-- | stage2/Stage2.scala | 4 | ||||
-rw-r--r-- | stage2/ToolsTasks.scala | 1 | ||||
-rw-r--r-- | stage2/plugins/Dotty.scala | 5 | ||||
-rw-r--r-- | test/test.scala | 5 |
21 files changed, 148 insertions, 142 deletions
diff --git a/compatibility/Dependency.java b/compatibility/Dependency.java index d491174..efb9214 100644 --- a/compatibility/Dependency.java +++ b/compatibility/Dependency.java @@ -3,6 +3,7 @@ import java.io.*; public interface Dependency{ public abstract String show(); + public abstract String moduleKey(); public abstract Boolean needsUpdateCompat(); public abstract Dependency[] dependenciesArray(); public abstract File[] dependencyClasspathArray(); diff --git a/plugins/essentials/DynamicOverrides.scala b/plugins/essentials/DynamicOverrides.scala index 4a3fe9e..1050f98 100644 --- a/plugins/essentials/DynamicOverrides.scala +++ b/plugins/essentials/DynamicOverrides.scala @@ -1,10 +1,12 @@ package cbt import cbt.eval.Eval trait DynamicOverrides extends BaseBuild{ - private val twitterEval = cached("eval"){ - new Eval{ - override lazy val impliedClassPath: List[String] = context.parentBuild.get.classpath.strings.toList//new ScalaCompilerDependency( context.cbtHasChanged, context.paths.mavenCache, scalaVersion ).classpath.strings.toList - override def classLoader = DynamicOverrides.this.getClass.getClassLoader + private val twitterEval = { + taskCache[DynamicOverrides]( "eval" ).memoize{ + new Eval{ + override lazy val impliedClassPath: List[String] = context.parentBuild.get.classpath.strings.toList//new ScalaCompilerDependency( context.cbtLastModified, context.paths.mavenCache, scalaVersion ).classpath.strings.toList + override def classLoader = DynamicOverrides.this.getClass.getClassLoader + } } } diff --git a/plugins/scalajs/ScalaJsLib.scala b/plugins/scalajs/ScalaJsLib.scala index 0355850..12c1c85 100644 --- a/plugins/scalajs/ScalaJsLib.scala +++ b/plugins/scalajs/ScalaJsLib.scala @@ -4,7 +4,7 @@ import java.io.File case class ScalaJsLib( scalaJsVersion: String, scalaVersion: String, cbtHasChanged: Boolean, classLoaderCache: ClassLoaderCache, mavenCache: File -)(implicit logger: Logger){ +)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]){ sealed trait ScalaJsOutputMode { def option: String def fileSuffix: String diff --git a/stage1/Cache.scala b/stage1/Cache.scala deleted file mode 100644 index a8036e5..0000000 --- a/stage1/Cache.scala +++ /dev/null @@ -1,14 +0,0 @@ -package cbt -/** -Caches exactly one value. -Is there a less boiler-platy way to achieve this, that doesn't -require creating an instance for each thing you want to cache? -*/ -class Cache[T]{ - private var value: Option[T] = None - def apply(value: => T) = this.synchronized{ - if(!this.value.isDefined) - this.value = Some(value) - this.value.get - } -} diff --git a/stage1/ContextImplementation.scala b/stage1/ContextImplementation.scala index 3b610c0..30db597 100644 --- a/stage1/ContextImplementation.scala +++ b/stage1/ContextImplementation.scala @@ -2,19 +2,19 @@ package cbt import java.io._ import java.lang._ -case class ContextImplementation( - projectDirectory: File, - cwd: File, - argsArray: Array[String], - enabledLoggersArray: Array[String], - startCompat: Long, - cbtHasChangedCompat: Boolean, - scalaVersionOrNull: String, - persistentCache: java.util.Map[AnyRef,AnyRef], - transientCache: java.util.Map[AnyRef,AnyRef], - cache: File, - cbtHome: File, - cbtRootHome: File, - compatibilityTarget: File, - parentBuildOrNull: BuildInterface -) extends Context
\ No newline at end of file +class ContextImplementation( + val projectDirectory: File, + val cwd: File, + val argsArray: Array[String], + val enabledLoggersArray: Array[String], + val startCompat: Long, + val cbtHasChangedCompat: Boolean, + val scalaVersionOrNull: String, + val persistentCache: java.util.Map[AnyRef,AnyRef], + val transientCache: java.util.Map[AnyRef,AnyRef], + val cache: File, + val cbtHome: File, + val cbtRootHome: File, + val compatibilityTarget: File, + val parentBuildOrNull: BuildInterface +) extends Context diff --git a/stage1/MavenRepository.scala b/stage1/MavenRepository.scala index 4184d2d..2ac7064 100644 --- a/stage1/MavenRepository.scala +++ b/stage1/MavenRepository.scala @@ -1,9 +1,13 @@ package cbt import java.io._ import java.net._ -case class MavenResolver( cbtHasChanged: Boolean, mavenCache: File, urls: URL* ){ - def bind( dependencies: MavenDependency* )(implicit logger: Logger): Seq[BoundMavenDependency] +case class MavenResolver( + cbtHasChanged: Boolean, mavenCache: File, urls: URL* +)( + implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef] +){ + def bind( dependencies: MavenDependency* ): Seq[BoundMavenDependency] = dependencies.map( BoundMavenDependency(cbtHasChanged,mavenCache,_,urls.to) ).to - def bindOne( dependency: MavenDependency )(implicit logger: Logger): BoundMavenDependency + def bindOne( dependency: MavenDependency ): BoundMavenDependency = BoundMavenDependency( cbtHasChanged, mavenCache, dependency, urls.to ) } diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index f0540b4..27c6402 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -44,6 +44,8 @@ case class Stage2Args( cache: File, cbtHome: File, compatibilityTarget: File +)( + implicit val transientCache: java.util.Map[AnyRef,AnyRef] ){ val ClassLoaderCache( logger, persistentCache ) = classLoaderCache } @@ -60,7 +62,7 @@ object Stage1{ ClassLoaderCache( logger, context.persistentCache ), context.cbtHome, context.cache - ) + )( context.transientCache ) classLoader .loadClass("cbt.Stage2") @@ -75,7 +77,7 @@ object Stage1{ def buildStage2( buildStage1: BuildStage1Result, classLoaderCache: ClassLoaderCache, cbtHome: File, cache: File - ): (Boolean, ClassLoader) = { + )(implicit transientCache: java.util.Map[AnyRef,AnyRef]): (Boolean, ClassLoader) = { import classLoaderCache.logger val lib = new Stage1Lib(logger) @@ -86,12 +88,12 @@ object Stage1{ val stage2sourceFiles = ( stage2.listFiles ++ (stage2 ++ "/plugins").listFiles ).toVector.filter(_.isFile).filter(_.toString.endsWith(".scala")) - + val cbtHasChanged = buildStage1.changed || lib.needsUpdate(stage2sourceFiles, stage2StatusFile) val cls = this.getClass.getClassLoader.loadClass("cbt.NailgunLauncher") - - val cbtDependency = CbtDependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, stage2Target, new File(buildStage1.compatibilityClasspath)) + + val cbtDependency = new CbtDependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, stage2Target, new File(buildStage1.compatibilityClasspath)) logger.stage1("Compiling stage2 if necessary") compile( @@ -102,7 +104,7 @@ object Stage1{ mavenCache, Seq("-deprecation","-feature","-unchecked"), classLoaderCache, zincVersion = constants.zincVersion, scalaVersion = constants.scalaVersion - ) + )(transientCache) logger.stage1(s"calling CbtDependency.classLoader") if( cbtHasChanged && classLoaderCache.cache.containsKey( cbtDependency.classpath.string ) ) { @@ -163,6 +165,7 @@ object Stage1{ ): Int = { val args = Stage1ArgsParser(_args.toVector) val logger = new Logger(args.enabledLoggers, start) + implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap logger.stage1(s"Stage1 start") val classLoaderCache = ClassLoaderCache( logger, persistentCache ) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 296581c..f0bb588 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -200,8 +200,9 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ classLoaderCache: ClassLoaderCache, zincVersion: String, scalaVersion: String + )( + implicit transientCache: java.util.Map[AnyRef, AnyRef] ): Option[File] = { - val classpath = Dependencies(dependencies).classpath val cp = classpath.string if(classpath.files.isEmpty) @@ -447,4 +448,26 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ else cache.cache.get( a.classpath.string, cl ).asInstanceOf[ClassLoader] } + +} + +import scala.reflect._ +import scala.language.existentials +case class PerClassCache(cache: java.util.Map[AnyRef,AnyRef], moduleKey: String)(implicit logger: Logger){ + def apply[D <: Dependency: ClassTag](key: AnyRef): MethodCache[D] = new MethodCache[D](key) + case class MethodCache[D <: Dependency: ClassTag](key: AnyRef){ + def memoize[T <: AnyRef](task: => T): T = { + val fullKey = (classTag[D].runtimeClass, moduleKey, key) + logger.transientCache("fetching key"+fullKey) + if( cache.containsKey(fullKey) ){ + logger.transientCache("found key"+fullKey) + cache.get(fullKey).asInstanceOf[T] + } else{ + val value = task + logger.transientCache("put key"+fullKey) + cache.put( fullKey, value ) + value + } + } + } } diff --git a/stage1/cbt.scala b/stage1/cbt.scala index 22242d7..01c9303 100644 --- a/stage1/cbt.scala +++ b/stage1/cbt.scala @@ -62,7 +62,7 @@ object `package`{ def classLoaderCache: ClassLoaderCache = new ClassLoaderCache( logger, persistentCache ) def cbtDependency = { import paths._ - CbtDependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, stage2Target, compatibilityTarget) + new CbtDependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, stage2Target, compatibilityTarget)(logger, transientCache) } def args: Seq[String] = argsArray.to def enabledLoggers: Set[String] = enabledLoggersArray.to @@ -79,7 +79,7 @@ object `package`{ scalaVersion: Option[String] = scalaVersion, cbtHome: File = cbtHome, parentBuild: Option[BuildInterface] = None - ): Context = ContextImplementation( + ): Context = new ContextImplementation( projectDirectory, cwd, args.to, diff --git a/stage1/logger.scala b/stage1/logger.scala index effdc35..8c8431a 100644 --- a/stage1/logger.scala +++ b/stage1/logger.scala @@ -41,6 +41,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) { final def git(msg: => String) = log(names.git, msg) final def pom(msg: => String) = log(names.pom, msg) final def dynamic(msg: => String) = log(names.dynamic, msg) + final def transientCache(msg: => String) = log(names.transientCache, msg) private object names{ val stage1 = "stage1" @@ -54,6 +55,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) { val pom = "pom" val git = "git" val dynamic = "dynamic" + val transientCache = "transientCache" } private def logUnguarded(name: String, msg: => String) = { diff --git a/stage1/resolver.scala b/stage1/resolver.scala index f4af73e..8e46135 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -8,6 +8,15 @@ import scala.xml._ trait DependencyImplementation extends Dependency{ implicit protected def logger: Logger protected def lib = new Stage1Lib(logger) + implicit protected def transientCache: java.util.Map[AnyRef,AnyRef] + + /** key used by taskCache to identify different objects that represent the same logical module */ + protected def moduleKey: String + /** + caches given value in context keyed with given key and projectDirectory + the context is fresh on every complete run of cbt + */ + protected lazy val taskCache = new PerClassCache(transientCache, moduleKey) /** CAREFUL: this is never allowed to return true for the same dependency more than @@ -101,11 +110,11 @@ trait DependencyImplementation extends Dependency{ ) def dependencies: Seq[Dependency] - private object transitiveDependenciesCache extends Cache[Seq[Dependency]] /** return dependencies in order of linearized dependence. this is a bit tricky. */ - def transitiveDependencies: Seq[Dependency] = transitiveDependenciesCache{ - lib.transitiveDependencies(this) - } + def transitiveDependencies: Seq[Dependency] = + taskCache[DependencyImplementation]( "transitiveDependencies" ).memoize{ + lib.transitiveDependencies(this) + } override def show: String = this.getClass.getSimpleName // ========== debug ========== @@ -113,65 +122,63 @@ trait DependencyImplementation extends Dependency{ } // TODO: all this hard codes the scala version, needs more flexibility -class ScalaCompilerDependency(cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(mavenCentral)) -class ScalaLibraryDependency (cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(mavenCentral)) -class ScalaReflectDependency (cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(mavenCentral)) +class ScalaCompilerDependency(cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(mavenCentral)) +class ScalaLibraryDependency (cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(mavenCentral)) +class ScalaReflectDependency (cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(mavenCentral)) -case class ScalaDependencies(cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit val logger: Logger) extends DependencyImplementation{ sd => - override final val needsUpdate = false - def targetClasspath = ClassPath() - def exportedClasspath = ClassPath() - def dependencies = Seq( +class ScalaDependencies(cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends Dependencies( + Seq( new ScalaCompilerDependency(cbtHasChanged, mavenCache, version), new ScalaLibraryDependency(cbtHasChanged, mavenCache, version), new ScalaReflectDependency(cbtHasChanged, mavenCache, version) ) -} +) -case class BinaryDependency( paths: Seq[File], dependencies: Seq[Dependency] )(implicit val logger: Logger) extends DependencyImplementation{ +case class BinaryDependency( paths: Seq[File], dependencies: Seq[Dependency] )(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef]) extends DependencyImplementation{ + assert(paths.nonEmpty) def exportedClasspath = ClassPath(paths) override def needsUpdate = false def targetClasspath = exportedClasspath + def moduleKey = this.getClass.getName ++ "(" ++ paths.mkString(", ") ++ ")" } /** Allows to easily assemble a bunch of dependencies */ -case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Logger) extends DependencyImplementation{ +case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef]) extends DependencyImplementation{ override def needsUpdate = dependencies.exists(_.needsUpdate) override def exportedClasspath = ClassPath() override def targetClasspath = ClassPath() + def moduleKey = this.getClass.getName ++ "(" ++ dependencies.map(_.moduleKey).mkString(", ") ++ ")" } -case class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{ - override def needsUpdate = false - override def targetClasspath = exportedClasspath - override def exportedClasspath = ClassPath( Seq(nailgunTarget, stage1Target) ) - val compatibilityDependency = CompatibilityDependency(cbtHasChanged, compatibilityTarget) - override def dependencies = Seq( - compatibilityDependency +class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, compatibilityTarget: File)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BinaryDependency( + Seq(nailgunTarget, stage1Target), + Seq( + new CompatibilityDependency(cbtHasChanged, compatibilityTarget) ) ++ MavenResolver(cbtHasChanged,mavenCache,mavenCentral).bind( MavenDependency("org.scala-lang","scala-library",constants.scalaVersion), MavenDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,constants.scalaXmlVersion) ) +){ + val compatibilityDependency = new CompatibilityDependency(cbtHasChanged, compatibilityTarget) + } -case class CompatibilityDependency(cbtHasChanged: Boolean, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{ - override def needsUpdate = false - override def targetClasspath = exportedClasspath - override def exportedClasspath = ClassPath( Seq(compatibilityTarget) ) - override def dependencies = Seq() -} -case class CbtDependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, stage2Target: File, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{ - override def needsUpdate = false - override def targetClasspath = exportedClasspath - override def exportedClasspath = ClassPath( Seq( stage2Target ) ) - val stage1Dependency = Stage1Dependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, compatibilityTarget) - override def dependencies = Seq( - stage1Dependency + +class CompatibilityDependency(cbtHasChanged: Boolean, compatibilityTarget: File)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BinaryDependency( + Seq(compatibilityTarget), Nil +) + +class CbtDependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, stage2Target: File, compatibilityTarget: File)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BinaryDependency( + Seq( stage2Target ), + Seq( + new Stage1Dependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, compatibilityTarget) ) ++ MavenResolver(cbtHasChanged, mavenCache,mavenCentral).bind( MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0"), MavenDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r") ) +){ + val stage1Dependency = new Stage1Dependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, compatibilityTarget) } case class Classifier(name: Option[String]) @@ -185,7 +192,9 @@ abstract class DependenciesProxy{ } class BoundMavenDependencies( cbtHasChanged: Boolean, mavenCache: File, urls: Seq[URL], mavenDependencies: Seq[MavenDependency] -)(implicit logger: Logger) extends Dependencies( +)( + implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef] +) extends Dependencies( mavenDependencies.map( BoundMavenDependency(cbtHasChanged,mavenCache,_,urls) ) ) case class MavenDependency( @@ -201,7 +210,10 @@ object MavenDependency{ // FIXME: take MavenResolver instead of mavenCache and repositories separately case class BoundMavenDependency( cbtHasChanged: Boolean, mavenCache: File, mavenDependency: MavenDependency, repositories: Seq[URL] -)(implicit val logger: Logger) extends ArtifactInfo with DependencyImplementation{ +)( + implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef] +) extends ArtifactInfo with DependencyImplementation{ + def moduleKey = this.getClass.getName ++ "(" ++ mavenDependency.serialize ++ ")" val MavenDependency( groupId, artifactId, version, classifier ) = mavenDependency assert( Option(groupId).collect{ @@ -251,17 +263,11 @@ case class BoundMavenDependency( StandardCharsets.UTF_8 ).mkString("\n").split(" ").head.trim } - - private object jarSha1Cache extends Cache[String] - def jarSha1: String = jarSha1Cache{ resolveHash("jar", true) } - - private object pomSha1Cache extends Cache[String] - def pomSha1: String = pomSha1Cache{ resolveHash("pom", false) } - private object jarCache extends Cache[File] - def jar: File = jarCache{ resolve("jar", Some(jarSha1), true) } - private object pomCache extends Cache[File] - def pom: File = pomCache{ resolve("pom", Some(pomSha1), false) } + def jarSha1: String = taskCache[BoundMavenDependency]("jarSha1").memoize{ resolveHash("jar", true) } + def pomSha1: String = taskCache[BoundMavenDependency]("pomSha1").memoize{ resolveHash("pom", false) } + def jar: File = taskCache[BoundMavenDependency]("jar").memoize{ resolve("jar", Some(jarSha1), true) } + def pom: File = taskCache[BoundMavenDependency]("pom").memoize{ resolve("pom", Some(pomSha1), false) } private def pomXml = XML.loadFile(pom.string) // ========== pom traversal ========== @@ -278,7 +284,7 @@ case class BoundMavenDependency( (parent \ "version").text ), repositories - )(logger) + ) }.flatMap(_.transitivePom) :+ this } diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 8b4a3a5..2fd34c7 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -9,6 +9,8 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge // will create new instances given the context, which means operations in the // overrides will happen multiple times and if they are not idempotent stuff likely breaks def context: Context + def moduleKey: String = "BaseBuild("+projectDirectory.string+")" + implicit def transientCache: java.util.Map[AnyRef,AnyRef] = context.transientCache // library available to builds implicit protected final val logger: Logger = context.logger @@ -59,7 +61,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge // FIXME: this should probably be removed Resolver( mavenCentral ).bind( "org.scala-lang" % "scala-library" % scalaVersion - ) :+ BinaryDependency(localJars, Nil) + ) ++ ( if(localJars.nonEmpty) Seq( BinaryDependency(localJars, Nil) ) else Nil ) // ========== paths ========== final private val defaultSourceDirectory = projectDirectory ++ "/src" @@ -135,15 +137,13 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge "-unchecked" ) - private object needsUpdateCache extends Cache[Boolean] - def needsUpdate: Boolean = needsUpdateCache( + def needsUpdate: Boolean = taskCache[BaseBuild]("needsUpdate").memoize[java.lang.Boolean]( context.cbtHasChanged || lib.needsUpdate( sourceFiles, compileStatusFile ) || transitiveDependencies.filterNot(_ == context.parentBuild).exists(_.needsUpdate) ) - private object compileCache extends Cache[Option[File]] - def compile: Option[File] = compileCache{ + def compile: Option[File] = taskCache[BaseBuild]("compile").memoize{ lib.compile( context.cbtHasChanged, needsUpdate || context.parentBuild.map(_.needsUpdate).getOrElse(false), @@ -153,7 +153,6 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge ) } - def mainClasses: Seq[Class[_]] = compile.toSeq.flatMap( lib.mainClasses( _, classLoader(classLoaderCache) ) ) def runClass: Option[String] = lib.runClass( mainClasses ).map( _.getName ) @@ -264,24 +263,6 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge def finalBuild: BuildInterface = this override def show = this.getClass.getSimpleName ++ "(" ++ projectDirectory.string ++ ")" - // TODO: allow people not provide the method name, maybe via macro - // TODO: pull this out into lib - /** - caches given value in context keyed with given key and projectDirectory - the context is fresh on every complete run of cbt - */ - def cached[T <: AnyRef](name: String)(task: => T): T = { - val cache = context.transientCache - val key = (projectDirectory,name) - if( cache.containsKey(key) ){ - cache.get(key).asInstanceOf[T] - } else{ - val value = task - cache.put( key, value ) - value - } - } - // a method that can be called only to trigger any side-effects final def `void` = () } diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index cf515bb..1b05214 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -32,8 +32,7 @@ trait BuildBuildWithoutEssentials extends BaseBuild{ override def dependencies = super.dependencies :+ context.cbtDependency def managedBuildDirectory: java.io.File = lib.realpath( projectDirectory.parent ) - private object managedBuildCache extends Cache[BuildInterface] - def managedBuild = managedBuildCache{ + def managedBuild = taskCache[BuildBuildWithoutEssentials]("managedBuild").memoize{ val managedBuildFile = projectDirectory++"/build.scala" logger.composition("Loading build at " ++ managedBuildDirectory.toString) val build = ( diff --git a/stage2/BuildDependency.scala b/stage2/BuildDependency.scala index 197a7a1..4b4fdc1 100644 --- a/stage2/BuildDependency.scala +++ b/stage2/BuildDependency.scala @@ -16,9 +16,12 @@ trait TriggerLoop extends DependencyImplementation{ } /** You likely want to use the factory method in the BasicBuild class instead of this. */ final case class DirectoryDependency(context: Context) extends TriggerLoop{ + override def toString = show override def show = this.getClass.getSimpleName ++ "(" ++ context.projectDirectory.string ++ ")" + def moduleKey = this.getClass.getName ++ "("+context.projectDirectory.string+")" lazy val logger = context.logger override lazy val lib: Lib = new Lib(logger) + def transientCache = context.transientCache private lazy val root = lib.loadRoot( context.copy(args=Seq()) ) lazy val build = root.finalBuild def exportedClasspath = ClassPath() diff --git a/stage2/GitDependency.scala b/stage2/GitDependency.scala index 650fd09..e27eff9 100644 --- a/stage2/GitDependency.scala +++ b/stage2/GitDependency.scala @@ -15,15 +15,14 @@ case class GitDependency( )(implicit val logger: Logger, classLoaderCache: ClassLoaderCache, context: Context ) extends DependencyImplementation{ import GitDependency._ override def lib = new Lib(logger) - + def moduleKey = this.getClass.getName ++ "(" ++ url ++ subDirectory.map("/" ++ _).getOrElse("") ++ "#" ++ ref ++ ")" + def transientCache = context.transientCache // TODO: add support for authentication via ssh and/or https // See http://www.codeaffine.com/2014/12/09/jgit-authentication/ private val GitUrl( _, domain, path ) = url private val credentialsFile = context.projectDirectory ++ "/git.login" - private object checkoutCache extends Cache[File] - private def authenticate(_git: CloneCommand) = if(!credentialsFile.exists){ _git @@ -36,7 +35,7 @@ case class GitDependency( _git.setCredentialsProvider( new UsernamePasswordCredentialsProvider(user, password) ) } - def checkout: File = checkoutCache{ + def checkout: File = taskCache[GitDependency]("checkout").memoize{ val checkoutDirectory = context.cache ++ s"/git/$domain/$path/$ref" val _git = if(checkoutDirectory.exists){ logger.git(s"Found existing checkout of $url#$ref in $checkoutDirectory") @@ -65,8 +64,7 @@ case class GitDependency( assert( actualRef == ref, s"actual ref '$actualRef' does not match expected ref '$ref'") checkoutDirectory } - private object dependencyCache extends Cache[DependencyImplementation] - def dependency = dependencyCache{ + def dependency = taskCache[GitDependency]("dependency").memoize{ DirectoryDependency( context.copy( projectDirectory = checkout ++ subDirectory.map("/" ++ _).getOrElse("") diff --git a/stage2/Lib.scala b/stage2/Lib.scala index 769cd97..c570ca3 100644 --- a/stage2/Lib.scala +++ b/stage2/Lib.scala @@ -86,7 +86,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ compileArgs: Seq[String], classLoaderCache: ClassLoaderCache, mavenCache: File - ): Option[File] = { + )(implicit transientCache: java.util.Map[AnyRef,AnyRef]): Option[File] = { if(sourceFiles.isEmpty){ None } else { @@ -101,7 +101,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ runMain( "scala.tools.nsc.ScalaDoc", args, - ScalaDependencies(cbtHasChanged,mavenCache,scalaVersion)(logger).classLoader(classLoaderCache) + new ScalaDependencies(cbtHasChanged,mavenCache,scalaVersion).classLoader(classLoaderCache) ) } lib.jarFile( diff --git a/stage2/PackageJars.scala b/stage2/PackageJars.scala index ff89284..3ecceb2 100644 --- a/stage2/PackageJars.scala +++ b/stage2/PackageJars.scala @@ -10,18 +10,15 @@ trait PackageJars extends BaseBuild with ArtifactInfo{ Seq(() => jar, () => docJar, () => srcJar) )( _() ).flatten - private object cacheJarBasicBuild extends Cache[Option[File]] - def jar: Option[File] = cacheJarBasicBuild{ + def jar: Option[File] = taskCache[PackageJars]("jar").memoize{ compile.flatMap( lib.jar( artifactId, scalaMajorVersion, version, _, jarTarget ) ) } - private object cacheSrcJarBasicBuild extends Cache[Option[File]] - def srcJar: Option[File] = cacheSrcJarBasicBuild{ + def srcJar: Option[File] = taskCache[PackageJars]("srcJar").memoize{ lib.srcJar( sourceFiles, artifactId, scalaMajorVersion, version, scalaTarget ) } - private object cacheDocBasicBuild extends Cache[Option[File]] - def docJar: Option[File] = cacheDocBasicBuild{ + def docJar: Option[File] = taskCache[PackageJars]("docJar").memoize{ lib.docJar( context.cbtHasChanged, scalaVersion, sourceFiles, compileClasspath, docTarget, diff --git a/stage2/Stage2.scala b/stage2/Stage2.scala index ab7b4fe..2884ddb 100644 --- a/stage2/Stage2.scala +++ b/stage2/Stage2.scala @@ -24,7 +24,7 @@ object Stage2 extends Stage2Base{ } val task = args.args.lift( taskIndex ) - val context: Context = ContextImplementation( + val context: Context = new ContextImplementation( args.cwd, args.cwd, args.args.drop( taskIndex +1 ).toArray, @@ -33,7 +33,7 @@ object Stage2 extends Stage2Base{ args.cbtHasChanged, null, args.persistentCache, - new HashMap, + args.transientCache, args.cache, args.cbtHome, args.cbtHome, diff --git a/stage2/ToolsTasks.scala b/stage2/ToolsTasks.scala index b92cb7a..839780a 100644 --- a/stage2/ToolsTasks.scala +++ b/stage2/ToolsTasks.scala @@ -15,6 +15,7 @@ class ToolsTasks( import paths._ private def Resolver( urls: URL* ) = MavenResolver(cbtHasChanged,mavenCache,urls: _*) implicit val logger: Logger = lib.logger + implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap def createMain: Unit = lib.createMain( cwd ) def createBuild: Unit = lib.createBuild( cwd ) def gui = NailgunLauncher.main(Array( diff --git a/stage2/plugins/Dotty.scala b/stage2/plugins/Dotty.scala index 8671fb6..fe949a3 100644 --- a/stage2/plugins/Dotty.scala +++ b/stage2/plugins/Dotty.scala @@ -14,8 +14,7 @@ trait Dotty extends BaseBuild{ context.classLoaderCache, dottyVersion = dottyVersion ) - private object compileCache extends Cache[Option[File]] - override def compile: Option[File] = compileCache{ + override def compile: Option[File] = taskCache[Dotty]("compile").memoize{ dottyLib.compile( needsUpdate || context.parentBuild.map(_.needsUpdate).getOrElse(false), sourceFiles, compileTarget, compileStatusFile, compileClasspath, @@ -41,7 +40,7 @@ class DottyLib( mavenCache: File, classLoaderCache: ClassLoaderCache, dottyVersion: String -){ +)(implicit transientCache: java.util.Map[AnyRef,AnyRef]){ val lib = new Lib(logger) import lib._ diff --git a/test/test.scala b/test/test.scala index ae6c301..332b61e 100644 --- a/test/test.scala +++ b/test/test.scala @@ -104,10 +104,11 @@ object Main{ val cache = cbtHome ++ "/cache" val mavenCache = cache ++ "/maven" val cbtHasChanged = true - def Resolver(urls: URL*) = MavenResolver(cbtHasChanged, mavenCache, urls: _*) + implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap + def Resolver(urls: URL*) = MavenResolver(cbtLastModified, mavenCache, urls: _*) { - val noContext = ContextImplementation( + val noContext = new ContextImplementation( cbtHome ++ "/test/nothing", cbtHome, Array(), |