aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md39
-rw-r--r--build/build.scala4
-rwxr-xr-xcbt38
-rw-r--r--compatibility/Context.java2
-rw-r--r--examples/build-info-example/build/build.scala2
-rw-r--r--examples/dynamic-overrides-example/build/build.scala31
-rw-r--r--examples/sonatype-release-example/build/build.scala2
-rw-r--r--libraries/eval/build/build/build.scala3
-rw-r--r--plugins/essentials/CommandLineOverrides.scala25
-rw-r--r--plugins/essentials/DynamicOverrides.scala66
-rw-r--r--plugins/essentials/PublishDynamic.scala8
-rw-r--r--plugins/essentials/Readme.md3
-rw-r--r--plugins/essentials/build/build.scala6
-rw-r--r--stage1/ContextImplementation.scala2
-rw-r--r--stage1/Stage1.scala4
-rw-r--r--stage1/cbt.scala4
-rw-r--r--stage1/constants.scala2
-rw-r--r--stage1/logger.scala2
-rw-r--r--stage1/resolver.scala13
-rw-r--r--stage2/BasicBuild.scala23
-rw-r--r--stage2/BuildBuild.scala32
-rw-r--r--stage2/Lib.scala14
-rw-r--r--stage2/PackageJars.scala3
-rw-r--r--stage2/Publish.scala3
-rw-r--r--stage2/Stage2.scala5
-rw-r--r--test/library-test/build/build.scala4
-rw-r--r--test/simple-fixed-cbt/build/build.scala4
-rw-r--r--test/simple-fixed/build/build.scala2
-rw-r--r--test/simple/build/build.scala2
-rw-r--r--test/test.scala67
30 files changed, 347 insertions, 68 deletions
diff --git a/README.md b/README.md
index 3d471bb..c22b5e6 100644
--- a/README.md
+++ b/README.md
@@ -267,6 +267,39 @@ Make sure you deleted your main projects class Main when running your tests.
Congratulations, you successfully created a dependent project and ran your tests.
+### Dynamic overrides and eval
+
+By making your Build extend trait `CommandLineOverrides` you get access to the `eval` and `with` commands.
+
+`eval` allows you to evaluate scala expressions in the scope of your build and show the result.
+You can use this to inspect your build.
+
+```
+$ cbt eval '1 + 1'
+2
+
+$ cbt eval scalaVersion
+2.11.8
+
+$ cbt eval 'sources.strings.mkString(":")'
+/a/b/c:/d/e/f
+```
+
+`with` allows you to inject code into your build (or rather a dynamically generated subclass).
+Follow the code with another task name and arguments if needed to run tasks of your modified build.
+You can use this to override build settings dynamically.
+
+```
+$ cbt with 'def hello = "Hello"' hello
+Hello
+
+$ cbt with 'def hello = "Hello"; def world = "World"; def helloWorld = hello ++ " " ++ world' helloWorld
+Hello World
+
+$ cbt with 'def version = super.version ++ "-SNAPSHOT"' package
+/a/b/c/e-SNAPSHOT.jar
+```
+
### Multi-projects Builds
A single build only handles a single project in CBT. So there isn't exactly
@@ -290,7 +323,7 @@ When you specify a particular version, CBT will use that one instead of the inst
You can specify one by adding one line right before `class Build`. It looks like this:
```
-// cbt:https://github.com/cvogt/cbt.git#75c32537cd8f29f9d12db37bf06ad942806f02393
+// cbt:https://github.com/cvogt/cbt.git#fe04889a6c3fe73ccdb4b19b44ac62e2b1a96f7d
class Build...
```
@@ -302,7 +335,7 @@ will not realize that and keep using the old version).
### Using CBT like a boss
Do you own your Build Tool or does your Build Tool own you? CBT makes it easy for YOU
-to be in control. We try to work on solid documentation, but even good
+to be in control. We try to work on solid documentation, but even good
documentation never tells the whole truth. Documentation can tell how to use
something and why things are happening, but only the code can tell all the
details of what exactly is happening. Reading the code can be intimidating for
@@ -319,11 +352,9 @@ to use it the next time. This means any changes you make are instantly reflected
This and the simple code make it super easy to fix bugs or add features yourself
and feed them back into main line CBT.
-
When debugging things, it can help to enable CBT's debug logging by passing
`-Dlog=all` to CBT (or a logger name instead of `all`).
-
Other design decisions
--------------------
diff --git a/build/build.scala b/build/build.scala
index 8770ef6..70fc268 100644
--- a/build/build.scala
+++ b/build/build.scala
@@ -6,7 +6,7 @@ class Build(val context: Context) extends Publish{
super.dependencies ++ Resolver(mavenCentral).bind(
MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
MavenDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r"),
- MavenDependency("com.typesafe.zinc","zinc","0.3.9"),
+ MavenDependency("com.typesafe.zinc","zinc",constants.zincVersion),
ScalaDependency("org.scala-lang.modules","scala-xml","1.0.5")
)
}
@@ -16,7 +16,7 @@ class Build(val context: Context) extends Publish{
def groupId: String = "org.cvogt"
- def defaultVersion: String = "0.1"
+ def version: String = "0.1"
def name: String = "cbt"
// Members declared in cbt.Publish
diff --git a/cbt b/cbt
index 47e41cd..1521b28 100755
--- a/cbt
+++ b/cbt
@@ -54,7 +54,7 @@ log () {
fi
}
-log "Checking for dependencies" $*
+log "Checking for dependencies" "$@"
which javac 2>&1 > /dev/null
javac_installed=$?
@@ -63,12 +63,12 @@ if [ ! $javac_installed -eq 0 ]; then
exit 1
fi
-# log "cutting javac version" $*
+# log "cutting javac version" "$@"
# javac_version=$(javac -version 2>&1) # e.g. "javac 1.8.0_u60"
# javac_version_update=${javac_version/javac 1./} # e.g. "8.0_u60"
# javac_version_minor_pointed=${javac_version_update%_*} # e.g. "8.0"
# javac_version_minor=${javac_version_minor_pointed%.*} # e.g. "8"
-# log "cutting javac version done" $*
+# log "cutting javac version done" "$@"
# if [ ! "$javac_version_minor" -ge "7" ]; then
# echo "You need to install javac version 1.7 or greater!" 2>&1
# echo "Current javac version is $javac_version" 2>&1
@@ -103,7 +103,7 @@ NG="$NG_EXECUTABLE --nailgun-port $NAILGUN_PORT"
CWD=$(pwd)
_DIR=$(dirname $(readlink "$0") 2>/dev/null || dirname "$0" 2>/dev/null )
-log "Find out real path. Build realpath if needed." $*
+log "Find out real path. Build realpath if needed." "$@"
export CBT_HOME=$(dirname $($_DIR/realpath/realpath.sh $0))
@@ -140,7 +140,7 @@ fi
which nc 2>&1 > /dev/null
nc_installed=$?
-log "Check for running nailgun with nc." $*
+log "Check for running nailgun with nc." "$@"
server_up=1
if [ $nc_installed -eq 0 ]; then
@@ -156,13 +156,13 @@ if [ $nailgun_installed -eq 1 ] || [ "$1" = "publishSigned" ] || [ "$2" = "publi
fi
if [ $use_nailgun -eq 0 ] && [ ! $server_up -eq 0 ]; then
- log "Starting background process (nailgun)" $*
+ log "Starting background process (nailgun)" "$@"
# try to start nailgun-server, just in case it's not up
$NG_SERVER 127.0.0.1:$NAILGUN_PORT >> $nailgun_out 2>> $nailgun_err &
fi
stage1 () {
- log "Checking for changes in cbt/nailgun_launcher" $*
+ log "Checking for changes in cbt/nailgun_launcher" "$@"
NAILGUN_INDICATOR=$NAILGUN$TARGET/cbt/NailgunLauncher.class
changed=0
for file in `ls $NAILGUN/*.java`; do
@@ -188,20 +188,20 @@ stage1 () {
fi
fi
- log "run CBT and loop if desired. This allows recompiling CBT itself as part of compile looping." $*
+ log "run CBT and loop if desired. This allows recompiling CBT itself as part of compile looping." "$@"
if [ $use_nailgun -eq 1 ]
then
- log "Running JVM directly" $*
+ log "Running JVM directly" "$@"
# -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:5005
# JVM options to improve startup time. See https://github.com/cvogt/cbt/pull/262
- java $JAVA_OPTS -Xmx6072m -Xss10M -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xverify:none -cp $NAILGUN$TARGET cbt.NailgunLauncher $(time_taken) "$CWD" $*
+ java $JAVA_OPTS -Xmx6072m -Xss10M -XX:MaxJavaStackTraceDepth=-1 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xverify:none -cp $NAILGUN$TARGET cbt.NailgunLauncher $(time_taken) "$CWD" "$@"
else
- log "Running via background process (nailgun)" $*
+ log "Running via background process (nailgun)" "$@"
for i in 0 1 2 3 4 5 6 7 8 9; do
- log "Adding classpath." $*
+ log "Adding classpath." "$@"
$NG ng-cp $NAILGUN$TARGET >> $nailgun_out 2>> $nailgun_err
- log "Checking if nailgun is up yet." $*
+ log "Checking if nailgun is up yet." "$@"
$NG cbt.NailgunLauncher check-alive >> $nailgun_out 2>> $nailgun_err
alive=$?
if [ $alive -eq 131 ] || [ $alive -eq 33 ]; then
@@ -210,22 +210,22 @@ stage1 () {
#elif [ $alive -eq 33 ]; then
break
else
- log "Nope. Sleeping for 0.5 seconds" $*
+ log "Nope. Sleeping for 0.5 seconds" "$@"
#if [ "$i" -gt 1 ]; then
# echo "Waiting for nailgun to start... (In case of problems try -Dlog=nailgun or check logs in cbt/nailgun_launcher/target/*.log)" 1>&2
#fi
fi
sleep 0.3
done
- log "Running CBT via Nailgun." $*
- $NG cbt.NailgunLauncher $(time_taken) "$CWD" $*
+ log "Running CBT via Nailgun." "$@"
+ $NG cbt.NailgunLauncher $(time_taken) "$CWD" "$@"
fi
exitCode=$?
- log "Done running CBT." $*
+ log "Done running CBT." "$@"
}
while true; do
- stage1 $*
+ stage1 "$@"
if [ ! "$1" = "loop" ]; then
break
fi
@@ -236,5 +236,5 @@ if [ $compiles -ne 0 ]; then
exitCode=1
fi
-log "Exiting CBT" $*
+log "Exiting CBT" "$@"
exit $exitCode
diff --git a/compatibility/Context.java b/compatibility/Context.java
index 921087f..5e03a7b 100644
--- a/compatibility/Context.java
+++ b/compatibility/Context.java
@@ -10,10 +10,10 @@ public abstract class Context{
public abstract String[] enabledLoggersArray();
public abstract Long startCompat();
public abstract Boolean cbtHasChangedCompat();
- public abstract String versionOrNull();
public abstract String scalaVersionOrNull(); // needed to propagate scalaVersion to dependendee builds
public abstract ConcurrentHashMap<String,Object> permanentKeys();
public abstract ConcurrentHashMap<Object,ClassLoader> permanentClassLoaders();
+ public abstract ConcurrentHashMap<Object,Object> taskCache();
public abstract File cache();
public abstract File cbtHome();
public abstract File cbtRootHome();
diff --git a/examples/build-info-example/build/build.scala b/examples/build-info-example/build/build.scala
index f6fc7a4..4d28598 100644
--- a/examples/build-info-example/build/build.scala
+++ b/examples/build-info-example/build/build.scala
@@ -4,8 +4,8 @@ import java.nio.file.Files._
class Build(val context: Context) extends PackageJars{
def name = "build-info-example"
def groupId = "cbt.examples"
- def defaultVersion = "0.1"
override def defaultScalaVersion = "2.11.8"
+ def version = "0.1"
override def compile = {
val file = (projectDirectory ++ "/BuildInfo.scala").toPath
val contents = s"""// generated file
diff --git a/examples/dynamic-overrides-example/build/build.scala b/examples/dynamic-overrides-example/build/build.scala
new file mode 100644
index 0000000..6cab975
--- /dev/null
+++ b/examples/dynamic-overrides-example/build/build.scala
@@ -0,0 +1,31 @@
+import cbt._
+class Build(val context: Context) extends DynamicOverrides with CommandLineOverrides{
+ def foo2 = "Build"
+ def bar2: String =
+ newBuild[Build]{"""
+ override def foo2 = "Bar2: "+Option(getClass.getName)
+ """}.foo2
+
+ def baz2: String =
+ newBuild[Build]{"""
+ override def foo2 = "Baz2: "+Option(getClass.getName)
+ override def baz2 = bar2
+ """}.baz2
+ def foo = "Build"
+
+ def bar: String = newBuild[Bar].bar
+ def baz: String = newBuild[Baz].baz
+ def bam: String = newBuild[Bam].baz
+}
+trait Bar extends Build{
+ override def bar: String = foo
+ override def foo = "Bar: "+getClass.getName
+}
+trait Baz extends Build{
+ override def foo = "Baz: "+getClass.getName
+ override def baz = bar
+}
+trait Bam extends Bar{
+ override def foo = "Baz: "+getClass.getName
+ override def baz = bar
+}
diff --git a/examples/sonatype-release-example/build/build.scala b/examples/sonatype-release-example/build/build.scala
index 6af452d..a3d19b9 100644
--- a/examples/sonatype-release-example/build/build.scala
+++ b/examples/sonatype-release-example/build/build.scala
@@ -4,7 +4,7 @@ import cbt._
class Build(val context: Context) extends SonatypeRelease {
def groupId: String = "com.github.rockjam"
- def defaultVersion: String = "0.0.15"
+ def version: String = "0.0.15"
def name: String = "cbt-sonatype"
def description: String = "Plugin for CBT to release artifacts to sonatype OSS"
diff --git a/libraries/eval/build/build/build.scala b/libraries/eval/build/build/build.scala
index 22349c7..b93554e 100644
--- a/libraries/eval/build/build/build.scala
+++ b/libraries/eval/build/build/build.scala
@@ -1,6 +1,7 @@
import cbt._
-class Build(val context: Context) extends BuildBuild{
+class Build(val context: Context) extends BuildBuildWithoutEssentials{
+ // this is used by the essentials plugin, so we can't depend on it
override def dependencies = super.dependencies ++ Seq(
plugins.scalaTest
)
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/PublishDynamic.scala b/plugins/essentials/PublishDynamic.scala
new file mode 100644
index 0000000..83cdeb1
--- /dev/null
+++ b/plugins/essentials/PublishDynamic.scala
@@ -0,0 +1,8 @@
+package cbt
+
+trait PublishDynamic extends Publish with DynamicOverrides{
+ def publishSnapshotLocal: Unit =
+ newBuild[PublishDynamic]{"""
+ override def version = super.version ++ "-SNAPSHOT"
+ """}.publishLocal
+}
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" )
+}
diff --git a/stage1/ContextImplementation.scala b/stage1/ContextImplementation.scala
index 91c54f4..152e606 100644
--- a/stage1/ContextImplementation.scala
+++ b/stage1/ContextImplementation.scala
@@ -10,10 +10,10 @@ case class ContextImplementation(
enabledLoggersArray: Array[String],
startCompat: Long,
cbtHasChangedCompat: Boolean,
- versionOrNull: String,
scalaVersionOrNull: String,
permanentKeys: ConcurrentHashMap[String,AnyRef],
permanentClassLoaders: ConcurrentHashMap[AnyRef,ClassLoader],
+ taskCache: ConcurrentHashMap[AnyRef,AnyRef],
cache: File,
cbtHome: File,
cbtRootHome: File,
diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala
index c94d1a4..79bf1d5 100644
--- a/stage1/Stage1.scala
+++ b/stage1/Stage1.scala
@@ -105,7 +105,7 @@ object Stage1{
cbtDependency.dependencyClasspath,
mavenCache,
Seq("-deprecation","-feature","-unchecked"), classLoaderCache,
- zincVersion = "0.3.9", scalaVersion = constants.scalaVersion
+ zincVersion = constants.zincVersion, scalaVersion = constants.scalaVersion
)
logger.stage1(s"calling CbtDependency.classLoader")
@@ -165,7 +165,7 @@ object Stage1{
val stage2Args = Stage2Args(
new File( args.args(0) ),
- args.args.drop(1).toVector,
+ args.args.drop(1).dropWhile(_ == "direct").toVector,
// launcher changes cause entire nailgun restart, so no need for them here
cbtHasChanged = cbtHasChanged,
classLoaderCache = classLoaderCache,
diff --git a/stage1/cbt.scala b/stage1/cbt.scala
index 7a239a1..c08a5f3 100644
--- a/stage1/cbt.scala
+++ b/stage1/cbt.scala
@@ -62,7 +62,6 @@ object `package`{
def args: Seq[String] = argsArray.to
def enabledLoggers: Set[String] = enabledLoggersArray.to
def scalaVersion = Option(scalaVersionOrNull)
- def version = Option(versionOrNull)
def parentBuild = Option(parentBuildOrNull)
def start: scala.Long = startCompat
def cbtHasChanged: scala.Boolean = cbtHasChangedCompat
@@ -72,7 +71,6 @@ object `package`{
args: Seq[String] = args,
enabledLoggers: Set[String] = enabledLoggers,
cbtHasChanged: Boolean = cbtHasChanged,
- version: Option[String] = version,
scalaVersion: Option[String] = scalaVersion,
cache: File = cache,
cbtHome: File = cbtHome,
@@ -84,10 +82,10 @@ object `package`{
enabledLoggers.to,
startCompat,
cbtHasChangedCompat,
- version.getOrElse(null),
scalaVersion.getOrElse(null),
permanentKeys,
permanentClassLoaders,
+ taskCache,
cache,
cbtHome,
cbtRootHome,
diff --git a/stage1/constants.scala b/stage1/constants.scala
index 437cf19..f0414bc 100644
--- a/stage1/constants.scala
+++ b/stage1/constants.scala
@@ -2,6 +2,6 @@ package cbt
object constants{
val scalaXmlVersion = "1.0.5"
val scalaVersion = "2.11.8"
- val zincVersion = "0.3.9"
+ val zincVersion = "0.3.12"
val scalaMajorVersion = scalaVersion.split("\\.").take(2).mkString(".")
}
diff --git a/stage1/logger.scala b/stage1/logger.scala
index 57f0cfa..effdc35 100644
--- a/stage1/logger.scala
+++ b/stage1/logger.scala
@@ -40,6 +40,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) {
final def test(msg: => String) = log(names.test, msg)
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)
private object names{
val stage1 = "stage1"
@@ -52,6 +53,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) {
val test = "test"
val pom = "pom"
val git = "git"
+ val dynamic = "dynamic"
}
private def logUnguarded(name: String, msg: => String) = {
diff --git a/stage1/resolver.scala b/stage1/resolver.scala
index 13e8e52..e45237d 100644
--- a/stage1/resolver.scala
+++ b/stage1/resolver.scala
@@ -11,6 +11,13 @@ trait DependencyImplementation extends Dependency{
implicit protected def logger: Logger
protected def lib = new Stage1Lib(logger)
+ /**
+ CAREFUL: this is never allowed to return true for the same dependency more than
+ once in a single cbt run. Otherwise we can end up with multiple classloaders
+ for the same classes since classLoaderRecursion recreates the classLoader when it
+ sees this flag and it can be called multiple times. Maybe we can find a safer
+ solution than this current state.
+ */
def needsUpdate: Boolean
//def cacheClassLoader: Boolean = false
private[cbt] def targetClasspath: ClassPath
@@ -137,7 +144,7 @@ case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Lo
}
case class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{
- override def needsUpdate = cbtHasChanged
+ override def needsUpdate = false
override def targetClasspath = exportedClasspath
override def exportedClasspath = ClassPath( Seq(nailgunTarget, stage1Target) )
val compatibilityDependency = CompatibilityDependency(cbtHasChanged, compatibilityTarget)
@@ -150,13 +157,13 @@ case class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTar
)
}
case class CompatibilityDependency(cbtHasChanged: Boolean, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{
- override def needsUpdate = cbtHasChanged
+ 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 = cbtHasChanged
+ override def needsUpdate = false
override def targetClasspath = exportedClasspath
override def exportedClasspath = ClassPath( Seq( stage2Target ) )
val stage1Dependency = Stage1Dependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, compatibilityTarget)
diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala
index 128d2f8..d8d1b8b 100644
--- a/stage2/BasicBuild.scala
+++ b/stage2/BasicBuild.scala
@@ -33,7 +33,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
// TODO: this should probably provide a nice error message if class has constructor signature
def copy(context: Context): BuildInterface = lib.copy(this.getClass, context).asInstanceOf[BuildInterface]
- def zincVersion = "0.3.9"
+ def zincVersion = constants.zincVersion
def dependencies: Seq[Dependency] =
// FIXME: this should probably be removed
@@ -244,4 +244,25 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
// ========== cbt internals ==========
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.taskCache
+ 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 b183745..5eb7622 100644
--- a/stage2/BuildBuild.scala
+++ b/stage2/BuildBuild.scala
@@ -1,21 +1,27 @@
package cbt
import java.nio.file._
-trait BuildBuild extends BaseBuild{
- private final val managedContext = context.copy(
+trait BuildBuild extends BuildBuildWithoutEssentials{
+ override def dependencies =
+ super.dependencies :+ plugins.essentials
+}
+trait BuildBuildWithoutEssentials extends BaseBuild{
+ protected final val managedContext = context.copy(
projectDirectory = managedBuildDirectory,
parentBuild=Some(this)
)
object plugins{
- final lazy val scalaTest = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalatest" )
- final lazy val sbtLayout = DirectoryDependency( managedContext.cbtHome ++ "/plugins/sbt_layout" )
- final lazy val scalaJs = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalajs" )
- final lazy val scalariform = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalariform" )
- final lazy val scalafmt = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalafmt" )
- final lazy val wartremover = DirectoryDependency( managedContext.cbtHome ++ "/plugins/wartremover" )
- final lazy val uberJar = DirectoryDependency( managedContext.cbtHome ++ "/plugins/uber-jar" )
- final lazy val sonatypeRelease = DirectoryDependency( managedContext.cbtHome ++ "/plugins/sonatype-release" )
+ // TODO: move this out of the OO
+ final lazy val scalaTest = DirectoryDependency( context.cbtHome ++ "/plugins/scalatest" )
+ final lazy val sbtLayout = DirectoryDependency( context.cbtHome ++ "/plugins/sbt_layout" )
+ final lazy val scalaJs = DirectoryDependency( context.cbtHome ++ "/plugins/scalajs" )
+ final lazy val scalariform = DirectoryDependency( context.cbtHome ++ "/plugins/scalariform" )
+ final lazy val scalafmt = DirectoryDependency( context.cbtHome ++ "/plugins/scalafmt" )
+ final lazy val wartremover = DirectoryDependency( context.cbtHome ++ "/plugins/wartremover" )
+ final lazy val uberJar = DirectoryDependency( context.cbtHome ++ "/plugins/uber-jar" )
+ final lazy val sonatypeRelease = DirectoryDependency( context.cbtHome ++ "/plugins/sonatype-release" )
+ final lazy val essentials = DirectoryDependency( context.cbtHome ++ "/plugins/essentials" )
}
override def dependencies =
@@ -63,6 +69,12 @@ trait BuildBuild extends BaseBuild{
throw new Exception(
"No file build.scala (lower case) found in " ++ projectDirectory.getPath
)
+ /*
+ // is this not needed?
+ } else if( projectDirectory.getParentFile.getName == "build" && projectDirectory.getParentFile.getParentFile.getName == "build" ){
+ // can't use essentiasy, when building essentials themselves
+ new BasicBuild( managedContext ) with BuildBuildWithoutEssentials
+ */
} else if( projectDirectory.getParentFile.getName == "build" ){
new BasicBuild( managedContext ) with BuildBuild
} else {
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index 25183a3..3f6242f 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -48,7 +48,19 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{
val rootBuildClassName = if( useBasicBuildBuild ) buildBuildClassName else buildClassName
try{
- if(useBasicBuildBuild) default( context ) else new cbt.BasicBuild( context.copy( projectDirectory = start ) ) with BuildBuild
+ if(useBasicBuildBuild)
+ default( context )
+ else if(
+ // essentials depends on eval, which has a build that depends on scalatest
+ // this means in these we can't depend on essentials
+ // hopefully we find a better way that this pretty hacky exclusion rule
+ context.projectDirectory == (context.cbtHome ++ "/plugins/essentials")
+ || context.projectDirectory == (context.cbtHome ++ "/libraries/eval")
+ || context.projectDirectory == (context.cbtHome ++ "/plugins/scalatest")
+ )
+ new cbt.BasicBuild( context.copy( projectDirectory = start ) ) with BuildBuildWithoutEssentials
+ else
+ new cbt.BasicBuild( context.copy( projectDirectory = start ) ) with BuildBuild
} catch {
case e:ClassNotFoundException if e.getMessage == rootBuildClassName =>
throw new Exception(s"no class $rootBuildClassName found in " ++ start.string)
diff --git a/stage2/PackageJars.scala b/stage2/PackageJars.scala
index a101993..ff89284 100644
--- a/stage2/PackageJars.scala
+++ b/stage2/PackageJars.scala
@@ -5,8 +5,7 @@ import java.io.File
trait PackageJars extends BaseBuild with ArtifactInfo{
def name: String
def artifactId = name
- def defaultVersion: String
- final def version = context.version getOrElse defaultVersion
+ def version: String
def `package`: Seq[File] = lib.concurrently( enableConcurrency )(
Seq(() => jar, () => docJar, () => srcJar)
)( _() ).flatten
diff --git a/stage2/Publish.scala b/stage2/Publish.scala
index 7e00620..c4c6a48 100644
--- a/stage2/Publish.scala
+++ b/stage2/Publish.scala
@@ -40,9 +40,6 @@ trait Publish extends PackageJars{
def publishLocal: Unit =
lib.publishLocal( sourceFiles, `package` :+ pom, context.paths.mavenCache, releaseFolder )
- def publishSnapshotLocal: Unit =
- copy( context.copy(version = Some(version+"-SNAPSHOT")) ).publishLocal
-
def isSnapshot: Boolean = version.endsWith("-SNAPSHOT")
override def copy(context: Context) = super.copy(context).asInstanceOf[Publish]
diff --git a/stage2/Stage2.scala b/stage2/Stage2.scala
index 3d5c244..34128ac 100644
--- a/stage2/Stage2.scala
+++ b/stage2/Stage2.scala
@@ -19,10 +19,9 @@ object Stage2 extends Stage2Base{
logger.stage2(s"Stage2 start")
val loop = args.args.lift(0) == Some("loop")
- val direct = args.args.lift(0) == Some("direct")
val cross = args.args.lift(0) == Some("cross")
- val taskIndex = if (loop || direct || cross) {
+ val taskIndex = if (loop || cross) {
1
} else {
0
@@ -37,9 +36,9 @@ object Stage2 extends Stage2Base{
logger.start,
args.cbtHasChanged,
null,
- null,
args.permanentKeys,
args.permanentClassLoaders,
+ new java.util.concurrent.ConcurrentHashMap,
args.cache,
args.cbtHome,
args.cbtHome,
diff --git a/test/library-test/build/build.scala b/test/library-test/build/build.scala
index d07e58e..85c09ac 100644
--- a/test/library-test/build/build.scala
+++ b/test/library-test/build/build.scala
@@ -1,9 +1,9 @@
import cbt._
-// cbt:https://github.com/cvogt/cbt.git#bf4ea112fe668fb7e2e95a2baca4989b16384783
+// cbt:https://github.com/cvogt/cbt.git#fe04889a6c3fe73ccdb4b19b44ac62e2b1a96f7d
class Build(val context: Context) extends BaseBuild with PackageJars{
def groupId = "cbt.test"
- def defaultVersion = "0.1"
+ def version = "0.1"
def name = "library-test"
override def dependencies =
diff --git a/test/simple-fixed-cbt/build/build.scala b/test/simple-fixed-cbt/build/build.scala
index 1d0640d..857f6b7 100644
--- a/test/simple-fixed-cbt/build/build.scala
+++ b/test/simple-fixed-cbt/build/build.scala
@@ -1,6 +1,6 @@
import cbt._
-// cbt:https://github.com/cvogt/cbt.git#bf4ea112fe668fb7e2e95a2baca4989b16384783
+// cbt:https://github.com/cvogt/cbt.git#fe04889a6c3fe73ccdb4b19b44ac62e2b1a96f7d
class Build(val context: cbt.Context) extends PackageJars{
override def dependencies = super.dependencies ++ Seq(
DirectoryDependency( context.cbtHome ++ "/test/library-test" )
@@ -9,6 +9,6 @@ class Build(val context: cbt.Context) extends PackageJars{
MavenDependency("com.spotify", "missinglink-core", "0.1.1")
)
def groupId: String = "cbt.test"
- def defaultVersion: String = "0.1"
+ def version: String = "0.1"
def name: String = "simple-fixed-cbt"
} \ No newline at end of file
diff --git a/test/simple-fixed/build/build.scala b/test/simple-fixed/build/build.scala
index a2bd584..a0b192a 100644
--- a/test/simple-fixed/build/build.scala
+++ b/test/simple-fixed/build/build.scala
@@ -5,7 +5,7 @@ class Build(context: cbt.Context) extends BasicBuild(context){
super.dependencies
++
Seq(
- GitDependency("https://github.com/cvogt/cbt.git", "908e05e296974fe67d8aaf9f094d97ff986905af", Some("test/library-test"))
+ GitDependency("https://github.com/cvogt/cbt.git", "fe04889a6c3fe73ccdb4b19b44ac62e2b1a96f7d", Some("test/library-test"))
)
++
Resolver(mavenCentral).bind(
diff --git a/test/simple/build/build.scala b/test/simple/build/build.scala
index 586daca..3d0e105 100644
--- a/test/simple/build/build.scala
+++ b/test/simple/build/build.scala
@@ -5,7 +5,7 @@ class Build(val context: cbt.Context) extends BaseBuild{
super.dependencies
++
Seq(
- GitDependency("https://github.com/cvogt/cbt.git", "908e05e296974fe67d8aaf9f094d97ff986905af", Some("test/library-test"))
+ GitDependency("https://github.com/cvogt/cbt.git", "fe04889a6c3fe73ccdb4b19b44ac62e2b1a96f7d", Some("test/library-test"))
) ++
// FIXME: make the below less verbose
Resolver( mavenCentral ).bind(
diff --git a/test/test.scala b/test/test.scala
index 039ee6a..0eb0bef 100644
--- a/test/test.scala
+++ b/test/test.scala
@@ -115,9 +115,9 @@ object Main{
start,
cbtHasChanged,
null,
- null,
new ConcurrentHashMap[String,AnyRef],
new ConcurrentHashMap[AnyRef,ClassLoader],
+ new java.util.concurrent.ConcurrentHashMap[AnyRef,AnyRef],
cache,
cbtHome,
cbtHome,
@@ -256,8 +256,69 @@ object Main{
{
val res = runCbt("../examples/wartremover-example", Seq("compile"))
assert(!res.exit0)
- assert(res.err.contains("var is disabled"), res.out)
- assert(res.err.contains("null is disabled"), res.out)
+ assert(res.err.contains("var is disabled"), res.err)
+ assert(res.err.contains("null is disabled"), res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("with","""def dummy = "1.2.3" """, "dummy"))
+ assert(res.exit0)
+ assert(res.out == "1.2.3\n", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("with","""def dummy = "1.2.3" """, "dummy"))
+ assert(res.exit0)
+ assert(res.out == "1.2.3\n", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("eval",""" scalaVersion; 1 + 1 """))
+ assert(res.exit0)
+ assert(res.out == "2\n", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("foo"))
+ assert(res.exit0)
+ assert(res.out == "Build\n", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("bar"))
+ assert(res.exit0)
+ assert(res.out startsWith "Bar: DynamicBuild", res.out)
+ assert(res.out startsWith "", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("baz"))
+ assert(res.exit0)
+ assert(res.out startsWith "Bar: DynamicBuild", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("bam"))
+ assert(res.exit0)
+ assert(res.out startsWith "Baz: DynamicBuild", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("foo2"))
+ assert(res.exit0)
+ assert(res.out == "Build\n", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("bar2"))
+ assert(res.exit0)
+ assert(res.out startsWith "Bar2: Some(DynamicBuild", res.out ++ res.err)
+ }
+
+ {
+ val res = runCbt("../examples/dynamic-overrides-example", Seq("baz2"))
+ assert(res.exit0)
+ assert(res.out startsWith "Bar2: Some(DynamicBuild", res.out ++ res.err)
}
{