summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Grossetie <ggrossetie@gmail.com>2018-06-28 16:36:59 +0200
committerTobias Roeser <le.petit.fou@web.de>2019-02-14 17:45:16 +0100
commitfc18309865baf869d9c6f7ff7879f33f4cc122e6 (patch)
tree45c3c5bc36c04d0d7774017d8d5fe33e8e6db6be
parentc29b678085b9417d55ea4e225786f99568cfeeb1 (diff)
downloadmill-fc18309865baf869d9c6f7ff7879f33f4cc122e6.tar.gz
mill-fc18309865baf869d9c6f7ff7879f33f4cc122e6.tar.bz2
mill-fc18309865baf869d9c6f7ff7879f33f4cc122e6.zip
Create a Play! module to compile the router
-rwxr-xr-xbuild.sc2
-rwxr-xr-xci/test-mill-0.sh2
-rw-r--r--contrib/playlib/src/mill/playlib/RouterGeneratorWorker.scala94
-rw-r--r--contrib/playlib/src/mill/playlib/RouterModule.scala52
-rw-r--r--contrib/playlib/test/resources/hello-world/core/conf/routes2
-rw-r--r--contrib/playlib/test/resources/hello-world/core/views/hello.scala.html (renamed from contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html)0
-rw-r--r--contrib/playlib/test/src/mill/playlib/HelloWorldRouterTests.scala77
7 files changed, 227 insertions, 2 deletions
diff --git a/build.sc b/build.sc
index 310f7060..fc58fff5 100755
--- a/build.sc
+++ b/build.sc
@@ -243,7 +243,7 @@ object contrib extends MillModule {
)
}
- object twirllib extends MillModule {
+ object playlib extends MillModule {
def moduleDeps = Seq(scalalib)
}
diff --git a/ci/test-mill-0.sh b/ci/test-mill-0.sh
index 92dc34c5..e8d8f67c 100755
--- a/ci/test-mill-0.sh
+++ b/ci/test-mill-0.sh
@@ -6,4 +6,4 @@ set -eux
git clean -xdf
# Run tests
-mill -i all {main,scalalib,scalajslib,contrib.twirllib,main.client,contrib.scalapblib}.test
+mill -i all {main,scalalib,scalajslib,contri.playlib,main.client,contrib.scalapblib}.test
diff --git a/contrib/playlib/src/mill/playlib/RouterGeneratorWorker.scala b/contrib/playlib/src/mill/playlib/RouterGeneratorWorker.scala
new file mode 100644
index 00000000..dd3a818c
--- /dev/null
+++ b/contrib/playlib/src/mill/playlib/RouterGeneratorWorker.scala
@@ -0,0 +1,94 @@
+package mill
+package playlib
+
+import java.io.File
+import java.net.URLClassLoader
+
+import ammonite.ops.Path
+import mill.eval.PathRef
+import mill.scalalib.CompilationResult
+
+class RouterGeneratorWorker {
+
+ private var routerGeneratorInstances = Option.empty[(Long, RouterGeneratorWorkerApi)]
+
+ private def router(routerClasspath: Agg[Path]) = {
+ val classloaderSig = routerClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum
+ routerGeneratorInstances match {
+ case Some((sig, instance)) if sig == classloaderSig => instance
+ case _ =>
+ val cl = new URLClassLoader(routerClasspath.map(_.toIO.toURI.toURL).toArray, null)
+ val routerCompilerClass = cl.loadClass("play.routes.compiler.RoutesCompiler")
+ val routesCompilerTaskClass = cl.loadClass("play.routes.compiler.RoutesCompiler$RoutesCompilerTask")
+ val routerCompilerTaskConstructor = routesCompilerTaskClass.getConstructor(
+ classOf[File],
+ cl.loadClass("scala.collection.Seq"),
+ classOf[Boolean],
+ classOf[Boolean],
+ classOf[Boolean])
+ val staticRoutesGeneratorModule = cl.loadClass("play.routes.compiler.StaticRoutesGenerator$").getField("MODULE$")
+ val injectedRoutesGeneratorModule = cl.loadClass("play.routes.compiler.InjectedRoutesGenerator$").getField("MODULE$")
+ val compileMethod = routerCompilerClass.getMethod("compile",
+ routesCompilerTaskClass,
+ cl.loadClass("play.routes.compiler.RoutesGenerator"),
+ classOf[java.io.File])
+ val instance = new RouterGeneratorWorkerApi {
+ override def compile(task: RoutesCompilerTask, generatorType: String = "injected", generatedDir: File): Either[Seq[CompilationResult], Seq[File]] = {
+ val args = Array[AnyRef](task.file: java.io.File,
+ task.additionalImports: scala.collection.Seq[String],
+ Boolean.box(true),
+ Boolean.box(true),
+ Boolean.box(false))
+ val routesCompilerTaskInstance = routerCompilerTaskConstructor.newInstance(args: _*).asInstanceOf[Object]
+ val routesGeneratorInstance = generatorType match {
+ case "injected" => injectedRoutesGeneratorModule.get(null)
+ case "static" => staticRoutesGeneratorModule.get(null)
+ case _ => throw new Exception(s"Unrecognized generator type: $generatorType. Use injected or static")
+ }
+ val result = compileMethod.invoke(null,
+ routesCompilerTaskInstance,
+ routesGeneratorInstance,
+ generatedDir)
+ result.asInstanceOf[Either[AnyVal, Seq[File]]] match {
+ case Right(value) => Right(value)
+ case Left(_) => Left(Seq(CompilationResult(Path(""), PathRef(Path(""))))) // FIXME: convert the error to a CompilationResult
+ }
+ }
+ }
+ routerGeneratorInstances = Some((classloaderSig, instance))
+ instance
+ }
+ }
+
+ def compile(routerClasspath: Agg[Path],
+ file: Path,
+ additionalImports: Seq[String],
+ forwardsRouter: Boolean,
+ reverseRouter: Boolean,
+ namespaceReverseRouter: Boolean,
+ dest: Path)
+ (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = {
+ val compiler = router(routerClasspath)
+
+ val result = compiler.compile(RoutesCompilerTask(file.toIO, additionalImports, forwardsRouter, reverseRouter, namespaceReverseRouter), generatedDir = dest.toIO)
+
+ result match {
+ case Right(_) =>
+ val zincFile = ctx.dest / 'zinc
+ mill.eval.Result.Success(CompilationResult(zincFile, PathRef(ctx.dest)))
+ case Left(_) => mill.eval.Result.Failure("Unable to compile the routes") // FIXME: convert the error to a Failure
+ }
+ }
+}
+
+trait RouterGeneratorWorkerApi {
+
+ def compile(task: RoutesCompilerTask, generatorType: String = "injected", generatedDir: File): Either[Seq[CompilationResult], Seq[File]]
+}
+
+case class RoutesCompilerTask(file: File, additionalImports: Seq[String], forwardsRouter: Boolean, reverseRouter: Boolean, namespaceReverseRouter: Boolean)
+
+object RouterGeneratorWorkerApi {
+
+ def routerGeneratorWorker = new RouterGeneratorWorker()
+}
diff --git a/contrib/playlib/src/mill/playlib/RouterModule.scala b/contrib/playlib/src/mill/playlib/RouterModule.scala
new file mode 100644
index 00000000..947e895b
--- /dev/null
+++ b/contrib/playlib/src/mill/playlib/RouterModule.scala
@@ -0,0 +1,52 @@
+package mill
+package playlib
+
+import coursier.{Cache, MavenRepository}
+import mill.scalalib.Lib.resolveDependencies
+import mill.scalalib._
+import mill.util.Loose
+
+trait RouterModule extends mill.Module {
+
+ def playVersion: T[String]
+
+ def routesFile: T[PathRef] = T {
+ val routesPath = millSourcePath / "conf" / "routes"
+ PathRef(routesPath)
+ }
+
+ def routerClasspath: 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::routes-compiler:${playVersion()}"
+ )
+ )
+ }
+
+ def routesAdditionalImport: Seq[String] = Seq(
+ "controllers.Assets.Asset",
+ "play.libs.F"
+ )
+
+ def generateForwardsRouter: Boolean = true
+
+ def generateReverseRouter: Boolean = true
+
+ def namespaceReverseRouter: Boolean = false
+
+ def compileRouter: T[CompilationResult] = T.persistent {
+ RouterGeneratorWorkerApi.routerGeneratorWorker
+ .compile(routerClasspath().map(_.path),
+ routesFile().path,
+ routesAdditionalImport,
+ generateForwardsRouter,
+ generateReverseRouter,
+ namespaceReverseRouter,
+ T.ctx().dest)
+ }
+} \ No newline at end of file
diff --git a/contrib/playlib/test/resources/hello-world/core/conf/routes b/contrib/playlib/test/resources/hello-world/core/conf/routes
new file mode 100644
index 00000000..7d5e5498
--- /dev/null
+++ b/contrib/playlib/test/resources/hello-world/core/conf/routes
@@ -0,0 +1,2 @@
+GET / controllers.HomeController.index
+GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
diff --git a/contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html b/contrib/playlib/test/resources/hello-world/core/views/hello.scala.html
index 3603fe07..3603fe07 100644
--- a/contrib/twirllib/test/resources/hello-world/core/views/hello.scala.html
+++ b/contrib/playlib/test/resources/hello-world/core/views/hello.scala.html
diff --git a/contrib/playlib/test/src/mill/playlib/HelloWorldRouterTests.scala b/contrib/playlib/test/src/mill/playlib/HelloWorldRouterTests.scala
new file mode 100644
index 00000000..03742714
--- /dev/null
+++ b/contrib/playlib/test/src/mill/playlib/HelloWorldRouterTests.scala
@@ -0,0 +1,77 @@
+package mill.playlib
+
+import ammonite.ops.{Path, cp, ls, mkdir, pwd, rm, _}
+import mill.util.{TestEvaluator, TestUtil}
+import utest.framework.TestPath
+import utest.{TestSuite, Tests, assert, _}
+
+object HelloWorldRouterTests extends TestSuite {
+
+ trait HelloBase extends TestUtil.BaseModule {
+ override def millSourcePath: Path = TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.')
+ }
+
+ trait HelloWorldModule extends mill.playlib.RouterModule {
+ def playVersion = "2.6.15"
+ }
+
+ object HelloWorld extends HelloBase {
+
+ object core extends HelloWorldModule {
+ override def playVersion = "2.6.14"
+ }
+ }
+
+ val resourcePath: Path = pwd / 'contrib / 'playlib / '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 tests: Tests = Tests {
+ 'twirlVersion - {
+
+ 'fromBuild - workspaceTest(HelloWorld) { eval =>
+ val Right((result, evalCount)) = eval.apply(HelloWorld.core.playVersion)
+
+ assert(
+ result == "2.6.14",
+ evalCount > 0
+ )
+ }
+ }
+ 'compileRouter - workspaceTest(HelloWorld) { eval =>
+ val Right((result, evalCount)) = eval.apply(HelloWorld.core.compileRouter)
+
+ val outputFiles = ls.rec(result.classes.path).filter(_.isFile)
+ val expectedClassfiles = Seq[RelPath](
+ RelPath("controllers/ReverseRoutes.scala"),
+ RelPath("controllers/routes.java"),
+ RelPath("router/Routes.scala"),
+ RelPath("router/RoutesPrefix.scala"),
+ RelPath("controllers/javascript/JavaScriptReverseRoutes.scala")
+ ).map(
+ eval.outPath / 'core / 'compileRouter / 'dest / _
+ )
+ assert(
+ result.classes.path == eval.outPath / 'core / 'compileRouter / 'dest,
+ outputFiles.nonEmpty,
+ outputFiles.forall(expectedClassfiles.contains),
+ outputFiles.size == 5,
+ evalCount > 0
+ )
+
+ // don't recompile if nothing changed
+ val Right((_, unchangedEvalCount)) = eval.apply(HelloWorld.core.compileRouter)
+
+ assert(unchangedEvalCount == 0)
+ }
+ }
+}