summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/testng/src/mill/testng/ResultEvent.java45
-rw-r--r--contrib/testng/src/mill/testng/TestNGFramework.java25
-rw-r--r--contrib/testng/src/mill/testng/TestNGInstance.java67
-rw-r--r--contrib/testng/src/mill/testng/TestNGRunner.java76
-rw-r--r--contrib/twirllib/src/mill/twirllib/TwirlModule.scala56
-rw-r--r--contrib/twirllib/src/mill/twirllib/TwirlWorker.scala119
-rw-r--r--contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html6
-rw-r--r--contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala75
8 files changed, 469 insertions, 0 deletions
diff --git a/contrib/testng/src/mill/testng/ResultEvent.java b/contrib/testng/src/mill/testng/ResultEvent.java
new file mode 100644
index 00000000..6e2a50d6
--- /dev/null
+++ b/contrib/testng/src/mill/testng/ResultEvent.java
@@ -0,0 +1,45 @@
+
+package mill.testng;
+
+import sbt.testing.*;
+import org.testng.ITestResult;
+
+public class ResultEvent {
+ static Event failure(ITestResult result){ return event(Status.Failure, result); }
+ static Event skipped(ITestResult result){ return event(Status.Skipped, result); }
+ static Event success(ITestResult result){ return event(Status.Success, result); }
+
+ static Event event(Status result, ITestResult testNGResult) {
+ return new Event() {
+ public String fullyQualifiedName() {
+ return testNGResult.getTestClass().getName();
+ }
+
+ public Fingerprint fingerprint() {
+ return TestNGFingerprint.instance;
+ }
+
+ public Selector selector() {
+ return new SuiteSelector();
+ }
+
+ public Status status() {
+ return result;
+ }
+
+ public OptionalThrowable throwable() {
+ if (result != Status.Success){
+ return new OptionalThrowable(testNGResult.getThrowable());
+ }else {
+ return new OptionalThrowable();
+ }
+ }
+
+ @Override
+ public long duration() {
+ return testNGResult.getEndMillis() - testNGResult.getStartMillis();
+ }
+ };
+ }
+ static String classNameOf(ITestResult result){ return result.getTestClass().getName(); }
+} \ No newline at end of file
diff --git a/contrib/testng/src/mill/testng/TestNGFramework.java b/contrib/testng/src/mill/testng/TestNGFramework.java
new file mode 100644
index 00000000..6e993fcc
--- /dev/null
+++ b/contrib/testng/src/mill/testng/TestNGFramework.java
@@ -0,0 +1,25 @@
+package mill.testng;
+
+
+
+import sbt.testing.*;
+
+
+public class TestNGFramework implements Framework {
+ public String name(){ return "TestNG"; }
+
+ public Fingerprint[] fingerprints() {
+ return new Fingerprint[]{TestNGFingerprint.instance};
+ }
+
+ @Override
+ public Runner runner(String[] args, String[] remoteArgs, ClassLoader classLoader) {
+ return new TestNGRunner(args, remoteArgs, classLoader);
+ }
+}
+
+class TestNGFingerprint implements AnnotatedFingerprint{
+ final public static TestNGFingerprint instance = new TestNGFingerprint();
+ public String annotationName(){return "org.testng.annotations.Test";}
+ public boolean isModule(){return false;}
+}
diff --git a/contrib/testng/src/mill/testng/TestNGInstance.java b/contrib/testng/src/mill/testng/TestNGInstance.java
new file mode 100644
index 00000000..4cf274d3
--- /dev/null
+++ b/contrib/testng/src/mill/testng/TestNGInstance.java
@@ -0,0 +1,67 @@
+package mill.testng;
+
+
+import org.testng.*;
+import sbt.testing.EventHandler;
+import sbt.testing.Logger;
+
+import com.beust.jcommander.JCommander;
+
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
+class TestNGListener implements ITestListener{
+ EventHandler basket;
+ String lastName = "";
+ public TestNGListener(EventHandler basket){
+ this.basket = basket;
+ }
+ public void onTestStart(ITestResult iTestResult) {
+ String newName = iTestResult.getTestClass().getName() + " " + iTestResult.getName() + " ";
+ if(!newName.equals(lastName)){
+ if (!lastName.equals("")){
+ System.out.println();
+ }
+ lastName = newName;
+ System.out.print(lastName);
+ }
+ }
+
+ public void onTestSuccess(ITestResult iTestResult) {
+ System.out.print('+');
+ basket.handle(ResultEvent.success(iTestResult));
+ }
+
+ public void onTestFailure(ITestResult iTestResult) {
+ System.out.print('X');
+ basket.handle(ResultEvent.failure(iTestResult));
+ }
+
+ public void onTestSkipped(ITestResult iTestResult) {
+ System.out.print('-');
+ basket.handle(ResultEvent.skipped(iTestResult));
+ }
+
+ public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) {
+ basket.handle(ResultEvent.failure(iTestResult));
+ }
+
+ public void onStart(ITestContext iTestContext) {}
+
+ public void onFinish(ITestContext iTestContext) {}
+}
+
+public class TestNGInstance extends TestNG{
+ public TestNGInstance(Logger[] loggers,
+ ClassLoader testClassLoader,
+ CommandLineArgs args,
+ EventHandler eventHandler) {
+ addClassLoader(testClassLoader);
+
+ this.addListener(new TestNGListener(eventHandler));
+
+ configure(args);
+ }
+}
+
+
diff --git a/contrib/testng/src/mill/testng/TestNGRunner.java b/contrib/testng/src/mill/testng/TestNGRunner.java
new file mode 100644
index 00000000..0ad05f76
--- /dev/null
+++ b/contrib/testng/src/mill/testng/TestNGRunner.java
@@ -0,0 +1,76 @@
+package mill.testng;
+
+import com.beust.jcommander.JCommander;
+import org.testng.CommandLineArgs;
+import sbt.testing.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+class TestNGTask implements Task {
+
+ TaskDef taskDef;
+ TestNGRunner runner;
+ CommandLineArgs cliArgs;
+ public TestNGTask(TaskDef taskDef,
+ TestNGRunner runner,
+ CommandLineArgs cliArgs){
+ this.taskDef = taskDef;
+ this.runner = runner;
+ this.cliArgs = cliArgs;
+ }
+
+ @Override
+ public String[] tags() {
+ return new String[0];
+ }
+
+ @Override
+ public Task[] execute(EventHandler eventHandler, Logger[] loggers) {
+ new TestNGInstance(
+ loggers,
+ runner.testClassLoader,
+ cliArgs,
+ eventHandler
+ ).run();
+ return new Task[0];
+ }
+
+ @Override
+ public TaskDef taskDef() {
+ return taskDef;
+ }
+}
+
+public class TestNGRunner implements Runner {
+ ClassLoader testClassLoader;
+ String[] args;
+ String[] remoteArgs;
+ public TestNGRunner(String[] args, String[] remoteArgs, ClassLoader testClassLoader) {
+ this.testClassLoader = testClassLoader;
+ this.args = args;
+ this.remoteArgs = remoteArgs;
+ }
+
+ public Task[] tasks(TaskDef[] taskDefs) {
+ CommandLineArgs cliArgs = new CommandLineArgs();
+ new JCommander(cliArgs, args); // args is an output parameter of the constructor!
+ if(cliArgs.testClass == null){
+ String[] names = new String[taskDefs.length];
+ for(int i = 0; i < taskDefs.length; i += 1){
+ names[i] = taskDefs[i].fullyQualifiedName();
+ }
+ cliArgs.testClass = String.join(",", names);
+ }
+ if (taskDefs.length == 0) return new Task[]{};
+ else return new Task[]{new TestNGTask(taskDefs[0], this, cliArgs)};
+ }
+
+ public String done() { return null; }
+
+ public String[] remoteArgs() { return remoteArgs; }
+
+ public String[] args() { return args; }
+}
diff --git a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala
new file mode 100644
index 00000000..2df70a1f
--- /dev/null
+++ b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala
@@ -0,0 +1,56 @@
+package mill
+package twirllib
+
+import coursier.{Cache, MavenRepository}
+import mill.define.Sources
+import mill.eval.PathRef
+import mill.scalalib.Lib.resolveDependencies
+import mill.scalalib._
+import mill.util.Loose
+
+import scala.io.Codec
+import scala.util.Properties
+
+trait TwirlModule extends mill.Module {
+
+ def twirlVersion: T[String]
+
+ def twirlSources: Sources = T.sources {
+ millSourcePath / 'views
+ }
+
+ def twirlClasspath: T[Loose.Agg[PathRef]] = T {
+ resolveDependencies(
+ Seq(
+ Cache.ivy2Local,
+ MavenRepository("https://repo1.maven.org/maven2")
+ ),
+ Lib.depToDependency(_, "2.12.4"),
+ Seq(
+ ivy"com.typesafe.play::twirl-compiler:${twirlVersion()}",
+ ivy"org.scala-lang.modules::scala-parser-combinators:1.1.0"
+ )
+ )
+ }
+
+ // REMIND currently it's not possible to override these default settings
+ private def twirlAdditionalImports: Seq[String] = Nil
+
+ private def twirlConstructorAnnotations: Seq[String] = Nil
+
+ private def twirlCodec: Codec = Codec(Properties.sourceEncoding)
+
+ private def twirlInclusiveDot: Boolean = false
+
+ def compileTwirl: T[CompilationResult] = T.persistent {
+ TwirlWorkerApi.twirlWorker
+ .compile(
+ twirlClasspath().map(_.path),
+ twirlSources().map(_.path),
+ T.ctx().dest,
+ twirlAdditionalImports,
+ twirlConstructorAnnotations,
+ twirlCodec,
+ twirlInclusiveDot)
+ }
+}
diff --git a/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala b/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala
new file mode 100644
index 00000000..f351ff2f
--- /dev/null
+++ b/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala
@@ -0,0 +1,119 @@
+package mill
+package twirllib
+
+import java.io.File
+import java.lang.reflect.Method
+import java.net.URLClassLoader
+
+import ammonite.ops.{Path, ls}
+import mill.eval.PathRef
+import mill.scalalib.CompilationResult
+
+import scala.io.Codec
+
+class TwirlWorker {
+
+ private var twirlInstanceCache = Option.empty[(Long, TwirlWorkerApi)]
+
+ private def twirl(twirlClasspath: Agg[Path]) = {
+ val classloaderSig = twirlClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum
+ twirlInstanceCache match {
+ case Some((sig, instance)) if sig == classloaderSig => instance
+ case _ =>
+ val cl = new URLClassLoader(twirlClasspath.map(_.toIO.toURI.toURL).toArray)
+ val twirlCompilerClass = cl.loadClass("play.twirl.compiler.TwirlCompiler")
+ val compileMethod = twirlCompilerClass.getMethod("compile",
+ classOf[java.io.File],
+ classOf[java.io.File],
+ classOf[java.io.File],
+ classOf[java.lang.String],
+ cl.loadClass("scala.collection.Seq"),
+ cl.loadClass("scala.collection.Seq"),
+ cl.loadClass("scala.io.Codec"),
+ classOf[Boolean])
+
+ val defaultAdditionalImportsMethod = twirlCompilerClass.getMethod("compile$default$5")
+ val defaultConstructorAnnotationsMethod = twirlCompilerClass.getMethod("compile$default$6")
+ val defaultCodecMethod = twirlCompilerClass.getMethod("compile$default$7")
+ val defaultFlagMethod = twirlCompilerClass.getMethod("compile$default$8")
+
+ val instance = new TwirlWorkerApi {
+ override def compileTwirl(source: File,
+ sourceDirectory: File,
+ generatedDirectory: File,
+ formatterType: String,
+ additionalImports: Seq[String],
+ constructorAnnotations: Seq[String],
+ codec: Codec,
+ inclusiveDot: Boolean) {
+ val o = compileMethod.invoke(null, source,
+ sourceDirectory,
+ generatedDirectory,
+ formatterType,
+ defaultAdditionalImportsMethod.invoke(null),
+ defaultConstructorAnnotationsMethod.invoke(null),
+ defaultCodecMethod.invoke(null),
+ defaultFlagMethod.invoke(null))
+ }
+ }
+ twirlInstanceCache = Some((classloaderSig, instance))
+ instance
+ }
+ }
+
+ def compile(twirlClasspath: Agg[Path],
+ sourceDirectories: Seq[Path],
+ dest: Path,
+ additionalImports: Seq[String],
+ constructorAnnotations: Seq[String],
+ codec: Codec,
+ inclusiveDot: Boolean)
+ (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = {
+ val compiler = twirl(twirlClasspath)
+
+ def compileTwirlDir(inputDir: Path) {
+ ls.rec(inputDir).filter(_.name.matches(".*.scala.(html|xml|js|txt)"))
+ .foreach { template =>
+ val extFormat = twirlExtensionFormat(template.name)
+ compiler.compileTwirl(template.toIO,
+ inputDir.toIO,
+ dest.toIO,
+ s"play.twirl.api.$extFormat",
+ additionalImports,
+ constructorAnnotations,
+ codec,
+ inclusiveDot
+ )
+ }
+ }
+
+ sourceDirectories.foreach(compileTwirlDir)
+
+ val zincFile = ctx.dest / 'zinc
+ val classesDir = ctx.dest / 'html
+
+ mill.eval.Result.Success(CompilationResult(zincFile, PathRef(classesDir)))
+ }
+
+ private def twirlExtensionFormat(name: String) =
+ if (name.endsWith("html")) "HtmlFormat"
+ else if (name.endsWith("xml")) "XmlFormat"
+ else if (name.endsWith("js")) "JavaScriptFormat"
+ else "TxtFormat"
+}
+
+trait TwirlWorkerApi {
+ def compileTwirl(source: File,
+ sourceDirectory: File,
+ generatedDirectory: File,
+ formatterType: String,
+ additionalImports: Seq[String],
+ constructorAnnotations: Seq[String],
+ codec: Codec,
+ inclusiveDot: Boolean)
+}
+
+object TwirlWorkerApi {
+
+ def twirlWorker = new TwirlWorker()
+}
diff --git a/contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html b/contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html
new file mode 100644
index 00000000..acadf615
--- /dev/null
+++ b/contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html
@@ -0,0 +1,6 @@
+@(title: String)
+<html>
+ <body>
+ <h1>@title</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala
new file mode 100644
index 00000000..01576975
--- /dev/null
+++ b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala
@@ -0,0 +1,75 @@
+package mill.twirllib
+
+import ammonite.ops.{Path, cp, ls, mkdir, pwd, rm, _}
+import mill.util.{TestEvaluator, TestUtil}
+import utest.framework.TestPath
+import utest.{TestSuite, Tests, assert, _}
+
+object HelloWorldTests extends TestSuite {
+
+ trait HelloBase extends TestUtil.BaseModule {
+ override def millSourcePath: Path = TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.')
+ }
+
+ trait HelloWorldModule extends mill.twirllib.TwirlModule {
+ def twirlVersion = "1.0.0"
+ }
+
+ object HelloWorld extends HelloBase {
+
+ object core extends HelloWorldModule {
+ override def twirlVersion = "1.3.15"
+ }
+ }
+
+ val resourcePath: Path = pwd / 'contrib / 'twirllib / 'test / 'resources / "hello-world"
+
+ def workspaceTest[T, M <: TestUtil.BaseModule](m: M, resourcePath: Path = resourcePath)
+ (t: TestEvaluator[M] => T)
+ (implicit tp: TestPath): T = {
+ val eval = new TestEvaluator(m)
+ rm(m.millSourcePath)
+ rm(eval.outPath)
+ mkdir(m.millSourcePath / up)
+ cp(resourcePath, m.millSourcePath)
+ t(eval)
+ }
+
+ def compileClassfiles: Seq[RelPath] = Seq[RelPath](
+ "hello.template.scala"
+ )
+
+ def tests: Tests = Tests {
+ 'twirlVersion - {
+
+ 'fromBuild - workspaceTest(HelloWorld) { eval =>
+ val Right((result, evalCount)) = eval.apply(HelloWorld.core.twirlVersion)
+
+ assert(
+ result == "1.3.15",
+ evalCount > 0
+ )
+ }
+ }
+ 'compileTwirl - workspaceTest(HelloWorld) { eval =>
+ val Right((result, evalCount)) = eval.apply(HelloWorld.core.compileTwirl)
+
+ val outputFiles = ls.rec(result.classes.path)
+ val expectedClassfiles = compileClassfiles.map(
+ eval.outPath / 'core / 'compileTwirl / 'dest / 'html / _
+ )
+ assert(
+ result.classes.path == eval.outPath / 'core / 'compileTwirl / 'dest / 'html,
+ outputFiles.nonEmpty,
+ outputFiles.forall(expectedClassfiles.contains),
+ outputFiles.size == 1,
+ evalCount > 0
+ )
+
+ // don't recompile if nothing changed
+ val Right((_, unchangedEvalCount)) = eval.apply(HelloWorld.core.compileTwirl)
+
+ assert(unchangedEvalCount == 0)
+ }
+ }
+}