From 47a93993a84c572b4a2cd4562b52ec552f36879a Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 8 Nov 2016 00:58:30 -0500 Subject: Add support for dynamic re-configuration. The exact precedence rule of override code vs original code may still need to be tweaked as we go along. --- plugins/essentials/CommandLineOverrides.scala | 25 ++++++++++ plugins/essentials/DynamicOverrides.scala | 66 +++++++++++++++++++++++++++ plugins/essentials/Readme.md | 3 ++ plugins/essentials/build/build.scala | 6 +++ 4 files changed, 100 insertions(+) create mode 100644 plugins/essentials/CommandLineOverrides.scala create mode 100644 plugins/essentials/DynamicOverrides.scala create mode 100644 plugins/essentials/Readme.md create mode 100644 plugins/essentials/build/build.scala (limited to 'plugins/essentials') diff --git a/plugins/essentials/CommandLineOverrides.scala b/plugins/essentials/CommandLineOverrides.scala new file mode 100644 index 0000000..32b8403 --- /dev/null +++ b/plugins/essentials/CommandLineOverrides.scala @@ -0,0 +1,25 @@ +package cbt +trait CommandLineOverrides extends DynamicOverrides{ + def `with`: Any = { + new lib.ReflectObject( + newBuild[DynamicOverrides]( + context.copy( + args = context.args.drop(2) + ) + )( s""" + ${context.args.lift(0).getOrElse("")} + """ ) + ){ + def usage = "" + }.callNullary(context.args.lift(1) orElse Some("void")) + } + def eval = { + new lib.ReflectObject( + newBuild[CommandLineOverrides]( + context.copy( + args = ( context.args.lift(0).map("println{ "+_+" }") ).toSeq + ) + ){""} + ){def usage = ""}.callNullary(Some("with")) + } +} diff --git a/plugins/essentials/DynamicOverrides.scala b/plugins/essentials/DynamicOverrides.scala new file mode 100644 index 0000000..0826f12 --- /dev/null +++ b/plugins/essentials/DynamicOverrides.scala @@ -0,0 +1,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] + } +} diff --git a/plugins/essentials/Readme.md b/plugins/essentials/Readme.md new file mode 100644 index 0000000..76d3756 --- /dev/null +++ b/plugins/essentials/Readme.md @@ -0,0 +1,3 @@ +Essential CBT plugins + +Not part of CBT's core to keep it slim and so they can have dependencies if needed. diff --git a/plugins/essentials/build/build.scala b/plugins/essentials/build/build.scala new file mode 100644 index 0000000..1288367 --- /dev/null +++ b/plugins/essentials/build/build.scala @@ -0,0 +1,6 @@ +import cbt._ +class Build(val context: Context) extends Plugin{ + override def dependencies = + super.dependencies :+ // don't forget super.dependencies here for scala-library, etc. + DirectoryDependency( context.cbtHome ++ "/libraries/eval" ) +} -- cgit v1.2.3