aboutsummaryrefslogtreecommitdiff
path: root/plugins/essentials/DynamicOverrides.scala
blob: 0826f12edd5d8e53e77eceebc419ccbcf77d1905 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
    }
  }

  protected [cbt] def overrides: String = ""

  // TODO: add support for Build inner classes
  def newBuild[T <: DynamicOverrides:scala.reflect.ClassTag]: DynamicOverrides with T = newBuild[T](context)("")
  def newBuild[T <: DynamicOverrides:scala.reflect.ClassTag](body: String): DynamicOverrides with T = newBuild[T](context)(body)
  def newBuild[T <: DynamicOverrides:scala.reflect.ClassTag](context: Context)(body: String): DynamicOverrides with T = {
    val mixinClass = scala.reflect.classTag[T].runtimeClass
    assert(mixinClass.getTypeParameters.size == 0)
    val mixin = if(
      mixinClass == classOf[Nothing]
      || mixinClass.getSimpleName == "Build"
    ) "" else " with "+mixinClass.getName
    import scala.collection.JavaConverters._
    val parent = Option(
      if(this.getClass.getName.startsWith("Evaluator__"))
        this.getClass.getName.dropWhile(_ != '$').drop(1).stripSuffix("$1")
      else
        this.getClass.getName
    ).getOrElse(
      throw new Exception( "You cannot have more than one newBuild call on the Stack right now." )
    )
    val overrides = "" // currently disables, but can be used to force overrides everywhere
    val name = if(mixin == "" && overrides == "" && body == ""){
      "Build"
    } else if(overrides == ""){
      val name = "DynamicBuild" + System.currentTimeMillis
      val code = s"""
        class $name(context: _root_.cbt.Context)
          extends $parent(context)$mixin{
            $body
        }
      """
      logger.dynamic("Dynamically generated code:\n" ++ code)
      twitterEval.compile(code)
      name
    } else {
      val name = "DynamicBuild" + System.currentTimeMillis
      val code = s"""
        class $name(context: _root_.cbt.Context)
          extends $parent(context)$mixin{
            $body
        }
        class ${name}Overrides(context: _root_.cbt.Context)
          extends $name(context){
            $overrides
        }
      """
      logger.dynamic("Dynamically generated code:\n" ++ code)
      twitterEval.compile(code)
      name+"Overrides"
    }

    val createBuild = twitterEval.apply[Context => T](s"new $name(_: _root_.cbt.Context)",false)
    createBuild( context ).asInstanceOf[DynamicOverrides with T]
  }
}