diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-07 21:10:06 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-07 21:11:03 -0800 |
commit | ee080e63971399ceb22fd8f059a97e956d9f0dcb (patch) | |
tree | aa4ce5a9b6647835fbdae11266621f13d24dcfcb /core/src | |
parent | ca02aef2c98079c695fa616c75ab05a693c9d512 (diff) | |
download | mill-ee080e63971399ceb22fd8f059a97e956d9f0dcb.tar.gz mill-ee080e63971399ceb22fd8f059a97e956d9f0dcb.tar.bz2 mill-ee080e63971399ceb22fd8f059a97e956d9f0dcb.zip |
- Allow main methods to return `Target[T]`s, so they can then be evaled by an external `Evaluator` that has the `Discovered` mapping available
- Basic integration tests for `T.command` entrypoint running in the `JavaCompilerJarTests` suite
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/main/scala/forge/define/Applicative.scala | 2 | ||||
-rw-r--r-- | core/src/main/scala/forge/define/Target.scala | 12 | ||||
-rw-r--r-- | core/src/main/scala/forge/discover/Router.scala | 7 | ||||
-rw-r--r-- | core/src/main/scala/forge/eval/Evaluator.scala | 25 | ||||
-rw-r--r-- | core/src/test/scala/forge/JavaCompileJarTests.scala | 51 |
5 files changed, 77 insertions, 20 deletions
diff --git a/core/src/main/scala/forge/define/Applicative.scala b/core/src/main/scala/forge/define/Applicative.scala index 6a4d1d0c..dfa0cf84 100644 --- a/core/src/main/scala/forge/define/Applicative.scala +++ b/core/src/main/scala/forge/define/Applicative.scala @@ -7,7 +7,7 @@ import scala.collection.mutable import scala.reflect.macros.blackbox.Context object Applicative { - trait Applyable[T]{ + trait Applyable[+T]{ @compileTimeOnly("Target#apply() can only be used with a T{...} block") def apply(): T = ??? } diff --git a/core/src/main/scala/forge/define/Target.scala b/core/src/main/scala/forge/define/Target.scala index 98bd1b7c..753a63e8 100644 --- a/core/src/main/scala/forge/define/Target.scala +++ b/core/src/main/scala/forge/define/Target.scala @@ -9,7 +9,7 @@ import play.api.libs.json.{Format, Json} import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context -abstract class Target[T] extends Target.Ops[T] with Applyable[T]{ +abstract class Target[+T] extends Target.Ops[T] with Applyable[T]{ /** * What other Targets does this Target depend on? */ @@ -27,8 +27,10 @@ abstract class Target[T] extends Target.Ops[T] with Applyable[T]{ def sideHash: Int = 0 } + object Target extends Applicative.Applyer[Target, Target]{ def underlying[A](v: Target[A]) = v + type Cacher = forge.define.Cacher[Target[_]] class Target0[T](t: T) extends Target[T]{ lazy val t0 = t @@ -46,7 +48,7 @@ object Target extends Applicative.Applyer[Target, Target]{ ) } - abstract class Ops[T]{ this: Target[T] => + abstract class Ops[+T]{ this: Target[T] => def map[V](f: T => V) = new Target.Mapped(this, f) def filter(f: T => Boolean) = this @@ -58,18 +60,18 @@ object Target extends Applicative.Applyer[Target, Target]{ def traverse[T](source: Seq[Target[T]]) = { new Traverse[T](source) } - class Traverse[T](val inputs: Seq[Target[T]]) extends Target[Seq[T]]{ + class Traverse[+T](val inputs: Seq[Target[T]]) extends Target[Seq[T]]{ def evaluate(args: Args) = { for (i <- 0 until args.length) yield args(i).asInstanceOf[T] } } - class Mapped[T, V](source: Target[T], f: T => V) extends Target[V]{ + class Mapped[+T, +V](source: Target[T], f: T => V) extends Target[V]{ def evaluate(args: Args) = f(args(0)) val inputs = List(source) } - class Zipped[T, V](source1: Target[T], source2: Target[V]) extends Target[(T, V)]{ + class Zipped[+T, +V](source1: Target[T], source2: Target[V]) extends Target[(T, V)]{ def evaluate(args: Args) = (args(0), args(1)) val inputs = List(source1, source2) } diff --git a/core/src/main/scala/forge/discover/Router.scala b/core/src/main/scala/forge/discover/Router.scala index 3d054e29..afb526c7 100644 --- a/core/src/main/scala/forge/discover/Router.scala +++ b/core/src/main/scala/forge/discover/Router.scala @@ -1,6 +1,7 @@ package forge.discover import ammonite.main.Compat +import forge.define.Target import sourcecode.Compat.Context import scala.annotation.StaticAnnotation @@ -56,8 +57,8 @@ object Router{ argSignatures: Seq[ArgSig[T]], doc: Option[String], varargs: Boolean, - invoke0: (T, Map[String, String], Seq[String]) => Result[Any]){ - def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Any] = { + invoke0: (T, Map[String, String], Seq[String]) => Result[Target[Any]]){ + def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Target[Any]] = { var remainingArgSignatures = argSignatures.toList @@ -375,7 +376,7 @@ class Router [C <: Context](val c: C) { forge.discover.Router.validate(Seq(..$readArgs)) match{ case forge.discover.Router.Result.Success(List(..$argNames)) => forge.discover.Router.Result.Success($arg.${meth.name.toTermName}(..$argNameCasts)) - case x => x + case x: forge.discover.Router.Result.Error => x } ) """ diff --git a/core/src/main/scala/forge/eval/Evaluator.scala b/core/src/main/scala/forge/eval/Evaluator.scala index 19cd3236..590b5534 100644 --- a/core/src/main/scala/forge/eval/Evaluator.scala +++ b/core/src/main/scala/forge/eval/Evaluator.scala @@ -48,13 +48,16 @@ class Evaluator(workspacePath: Path, externalInputs.toIterator.map(results).toVector.hashCode + group.toIterator.map(_.sideHash).toVector.hashCode() - val primeLabel = labeling(terminals.items(0)).segments - - - val targetDestPath = workspacePath / primeLabel - val metadataPath = targetDestPath / up / (targetDestPath.last + ".forge.json") + val (targetDestPath, metadataPath) = labeling.get(terminals.items(0)) match{ + case Some(labeling) => + val targetDestPath = workspacePath / labeling.segments + val metadataPath = targetDestPath / up / (targetDestPath.last + ".forge.json") + (targetDestPath, Some(metadataPath)) + case None => (null, None) + } val cached = for{ + metadataPath <- metadataPath json <- scala.util.Try(Json.parse(read.getInputStream(metadataPath))).toOption (cachedHash, terminalResults) <- Json.fromJson[(Int, Seq[JsValue])](json).asOpt if cachedHash == inputsHash @@ -71,11 +74,13 @@ class Evaluator(workspacePath: Path, case _ => val (newResults, newEvaluated, terminalResults) = evaluateGroup(group, results, targetDestPath) - write.over( - metadataPath, - Json.prettyPrint( - Json.toJson(inputsHash -> terminals.toList.map(terminalResults)) - ), + metadataPath.foreach( + write.over( + _, + Json.prettyPrint( + Json.toJson(inputsHash -> terminals.toList.map(terminalResults)) + ), + ) ) (newResults, newEvaluated) diff --git a/core/src/test/scala/forge/JavaCompileJarTests.scala b/core/src/test/scala/forge/JavaCompileJarTests.scala index 6ce02149..92e1d0e9 100644 --- a/core/src/test/scala/forge/JavaCompileJarTests.scala +++ b/core/src/test/scala/forge/JavaCompileJarTests.scala @@ -1,7 +1,7 @@ package forge -import ammonite.ops._ +import ammonite.ops._, ImplicitWd._ import forge.define.Target import forge.discover.Discovered import forge.eval.{Evaluator, PathRef} @@ -44,10 +44,20 @@ object JavaCompileJarTests extends TestSuite{ def allSources = T{ ls.rec(sourceRoot().path).map(PathRef(_)) } def classFiles = T{ compileAll(allSources) } def jar = T{ jarUp(resourceRoot, classFiles) } + + @forge.discover.Router.main + def run(mainClsName: String): Target[CommandResult] = T.command{ + %%('java, "-cp", classFiles().path, mainClsName) + } } import Build._ val mapping = Discovered.mapping(Build) + def eval[T](t: Target[T]): (T, Int) = { + val evaluator = new Evaluator(workspacePath, mapping) + val evaluated = evaluator.evaluate(OSet(t)) + (evaluated.values(0).asInstanceOf[T], evaluated.evaluated.size) + } def check(targets: OSet[Target[_]], expected: OSet[Target[_]]) = { val evaluator = new Evaluator(workspacePath, mapping) @@ -113,6 +123,45 @@ object JavaCompileJarTests extends TestSuite{ val executed = %%('java, "-cp", workspacePath/'jar, "test.Foo")(workspacePath).out.string assert(executed == (31337 + 271828) + "\n") + + println("="*20 + "Run Main" + "="*20) + for(i <- 0 until 3){ + // Build.run is not cached, so every time we eval it it has to + // re-evaluate + val (runOutput, evalCount) = eval(Build.run("test.Foo")) + assert( + runOutput.out.string == (31337 + 271828) + "\n", + evalCount == 1 + ) + } + + val ex = intercept[ammonite.ops.ShelloutException]{ + eval(Build.run("test.BarFour")) + } + assert(ex.getMessage.contains("Could not find or load main class")) + + append( + sourceRootPath / "Bar.java", + """ + class BarFour{ + public static void main(String[] args){ + System.out.println("New Cls!"); + } + } + """ + ) + val (runOutput2, evalCount2) = eval(Build.run("test.BarFour")) + assert( + runOutput2.out.string == "New Cls!\n", + evalCount2 == 5 + ) + val (runOutput3, evalCount3) = eval(Build.run("test.BarFour")) + assert( + runOutput3.out.string == "New Cls!\n", + evalCount3 == 1 + ) + + } } } |