summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gregory <DavidGregory084@users.noreply.github.com>2018-10-31 20:44:53 +0000
committerTobias Roeser <le.petit.fou@web.de>2018-10-31 21:44:52 +0100
commit7b4ced648ecd9b79b3a16d67552f0bb69f4dd543 (patch)
tree2067f545668e03605fb1704ab8286cccb152f6cf
parent099fdb8defb7d2c8316da94d749c0c23088e0dc9 (diff)
downloadmill-7b4ced648ecd9b79b3a16d67552f0bb69f4dd543.tar.gz
mill-7b4ced648ecd9b79b3a16d67552f0bb69f4dd543.tar.bz2
mill-7b4ced648ecd9b79b3a16d67552f0bb69f4dd543.zip
Add tut contrib module (#464)
* Add tut contrib module * Add TutModule tests and documentation * Use Path instead of PathRef for tut target directory * Use the correct scala version in TutModule * Ensure resolving tut doesn't bring in extra scala-library jars * Ensure MILL_VERSION system property is set in tut tests * Fork to run tut to fix classpath problems, add test with library usage * Follow convention w.r.t. publishVersion in testArgs * Add Scaladoc to TutModule * Don't supply a default version of Tut * Update docs to account for mandatory tutVersion setting * Inline tutArgs, otherwise Tut does not recompile when sources change
-rwxr-xr-xbuild.sc6
-rw-r--r--contrib/tut/src/mill/contrib/tut/TutModule.scala132
-rw-r--r--contrib/tut/test/src/mill/contrib/tut/TutTests.scala124
-rw-r--r--contrib/tut/test/tut-with-libraries/TutWithLibraries.md10
-rw-r--r--contrib/tut/test/tut/TutExample.md3
-rw-r--r--docs/pages/9 - Contrib Modules.md56
-rw-r--r--main/core/src/mill/util/JsonFormatters.scala7
7 files changed, 337 insertions, 1 deletions
diff --git a/build.sc b/build.sc
index aa1cf428..878f5613 100755
--- a/build.sc
+++ b/build.sc
@@ -250,6 +250,10 @@ object contrib extends MillModule {
}
}
+ object tut extends MillModule {
+ def moduleDeps = Seq(scalalib)
+ def testArgs = Seq("-DMILL_VERSION=" + build.publishVersion()._2)
+ }
}
@@ -362,7 +366,7 @@ def launcherScript(shellJvmArgs: Seq[String],
}
object dev extends MillModule{
- def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, contrib.scalapblib)
+ def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, contrib.scalapblib, contrib.tut)
def forkArgs =
(
diff --git a/contrib/tut/src/mill/contrib/tut/TutModule.scala b/contrib/tut/src/mill/contrib/tut/TutModule.scala
new file mode 100644
index 00000000..f051a465
--- /dev/null
+++ b/contrib/tut/src/mill/contrib/tut/TutModule.scala
@@ -0,0 +1,132 @@
+package mill
+package contrib.tut
+
+import ammonite.ops._
+import coursier.MavenRepository
+import mill.scalalib._
+import scala.util.matching.Regex
+
+/**
+ * Tut is a documentation tool which compiles and evaluates Scala code in documentation files and provides various options for configuring how the results will be displayed in the compiled documentation.
+ *
+ * Extending this trait declares a Scala module which compiles markdown, HTML and `.txt` files in the `tut` folder of the module with Tut.
+ *
+ * By default the resulting documents are simply placed in the Mill build output folder but they can be placed elsewhere by overriding the [[mill.contrib.tut.TutModule#tutTargetDirectory]] task.
+ *
+ * For example:
+ *
+ * {{{
+ * // build.sc
+ * import mill._, scalalib._, contrib.tut.__
+ *
+ * object example extends TutModule {
+ * def scalaVersion = "2.12.6"
+ * def tutVersion = "0.6.7"
+ * }
+ * }}}
+ *
+ * This defines a project with the following layout:
+ *
+ * {{{
+ * build.sc
+ * example/
+ * src/
+ * tut/
+ * resources/
+ * }}}
+ *
+ * In order to compile documentation we can execute the `tut` task in the module:
+ *
+ * {{{
+ * sh> mill example.tut
+ * }}}
+ */
+trait TutModule extends ScalaModule {
+ /**
+ * This task determines where documentation files must be placed in order to be compiled with Tut. By default this is the `tut` folder at the root of the module.
+ */
+ def tutSourceDirectory = T.sources { millSourcePath / 'tut }
+
+ /**
+ * A task which determines where the compiled documentation files will be placed. By default this is simply the Mill build's output folder for this task,
+ * but this can be reconfigured so that documentation goes to the root of the module (e.g. `millSourcePath`) or to a dedicated folder (e.g. `millSourcePath / 'docs`)
+ */
+ def tutTargetDirectory: T[Path] = T { T.ctx().dest }
+
+ /**
+ * A task which determines what classpath is used when compiling documentation. By default this is configured to use the same inputs as the [[mill.contrib.tut.TutModule#runClasspath]],
+ * except for using [[mill.contrib.tut.TutModule#tutIvyDeps]] rather than the module's [[mill.contrib.tut.TutModule#runIvyDeps]].
+ */
+ def tutClasspath: T[Agg[PathRef]] = T {
+ // Same as runClasspath but with tut added to ivyDeps from the start
+ // This prevents duplicate, differently versioned copies of scala-library ending up on the classpath which can happen when resolving separately
+ transitiveLocalClasspath() ++
+ resources() ++
+ localClasspath() ++
+ unmanagedClasspath() ++
+ tutIvyDeps()
+ }
+
+ /**
+ * A task which determines the scalac plugins which will be used when compiling code examples with Tut. The default is to use the [[mill.contrib.tut.TutModule#scalacPluginIvyDeps]] for the module.
+ */
+ def tutScalacPluginIvyDeps: T[Agg[Dep]] = scalacPluginIvyDeps()
+
+ /**
+ * A [[scala.util.matching.Regex]] task which will be used to determine which files should be compiled with tut. The default pattern is as follows: `.*\.(md|markdown|txt|htm|html)`.
+ */
+ def tutNameFilter: T[Regex] = T { """.*\.(md|markdown|txt|htm|html)""".r }
+
+ /**
+ * The scalac options which will be used when compiling code examples with Tut. The default is to use the [[mill.contrib.tut.TutModule#scalacOptions]] for the module,
+ * but filtering out options which are problematic in the REPL, e.g. `-Xfatal-warnings`, `-Ywarn-unused-imports`.
+ */
+ def tutScalacOptions: T[Seq[String]] =
+ scalacOptions().filterNot(Set(
+ "-Ywarn-unused:imports",
+ "-Ywarn-unused-import",
+ "-Ywarn-dead-code",
+ "-Xfatal-warnings"
+ ))
+
+ /**
+ * The version of Tut to use.
+ */
+ def tutVersion: T[String]
+
+ /**
+ * A task which determines how to fetch the Tut jar file and all of the dependencies required to compile documentation for the module and returns the resulting files.
+ */
+ def tutIvyDeps: T[Agg[PathRef]] = T {
+ Lib.resolveDependencies(
+ repositories :+ MavenRepository(s"https://dl.bintray.com/tpolecat/maven"),
+ Lib.depToDependency(_, scalaVersion()),
+ compileIvyDeps() ++ transitiveIvyDeps() ++ Seq(
+ ivy"org.tpolecat::tut-core:${tutVersion()}"
+ )
+ )
+ }
+
+ /**
+ * A task which performs the dependency resolution for the scalac plugins to be used with Tut.
+ */
+ def tutPluginJars: T[Agg[PathRef]] = resolveDeps(tutScalacPluginIvyDeps)()
+
+ /**
+ * Run Tut using the configuration specified in this module. The working directory used is the [[mill.contrib.tut.TutModule#millSourcePath]].
+ */
+ def tut: T[CommandResult] = T {
+ val in = tutSourceDirectory().head.path.toIO.getAbsolutePath
+ val out = tutTargetDirectory().toIO.getAbsolutePath
+ val re = tutNameFilter()
+ val opts = tutScalacOptions()
+ val pOpts = tutPluginJars().map(pathRef => "-Xplugin:" + pathRef.path.toIO.getAbsolutePath)
+ val tutArgs = List(in, out, re.pattern.toString) ++ opts ++ pOpts
+ %%(
+ 'java,
+ "-cp", tutClasspath().map(_.path.toIO.getAbsolutePath).mkString(java.io.File.pathSeparator),
+ "tut.TutMain",
+ tutArgs
+ )(wd = millSourcePath)
+ }
+}
diff --git a/contrib/tut/test/src/mill/contrib/tut/TutTests.scala b/contrib/tut/test/src/mill/contrib/tut/TutTests.scala
new file mode 100644
index 00000000..fd369eed
--- /dev/null
+++ b/contrib/tut/test/src/mill/contrib/tut/TutTests.scala
@@ -0,0 +1,124 @@
+package mill.contrib
+package tut
+
+import ammonite.ops._
+import mill._
+import mill.eval.Result._
+import mill.scalalib._
+import mill.util.{TestEvaluator, TestUtil}
+import utest._
+import utest.framework.TestPath
+
+object TutTests extends TestSuite {
+
+ trait TutTestModule extends TestUtil.BaseModule with TutModule {
+ def millSourcePath = TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.')
+ def scalaVersion = "2.12.4"
+ def tutVersion = "0.6.7"
+ }
+
+ object TutTest extends TutTestModule
+
+ object TutCustomTest extends TutTestModule {
+ def tutTargetDirectory = millSourcePath
+ }
+
+ object TutLibrariesTest extends TutTestModule {
+ def ivyDeps = Agg(ivy"org.typelevel::cats-core:1.4.0")
+ def tutSourceDirectory = T.sources { resourcePathWithLibraries }
+ def scalacPluginIvyDeps = Agg(ivy"org.spire-math::kind-projector:0.9.8")
+ }
+
+ val resourcePath = pwd / 'contrib / 'tut / 'test / 'tut
+ val resourcePathWithLibraries = pwd / 'contrib / 'tut / 'test / "tut-with-libraries"
+
+ def workspaceTest[T](m: TestUtil.BaseModule, resourcePath: Path = resourcePath)
+ (t: TestEvaluator => T)
+ (implicit tp: TestPath): T = {
+ val eval = new TestEvaluator(m)
+ rm(m.millSourcePath)
+ rm(eval.outPath)
+ mkdir(m.millSourcePath)
+ cp(resourcePath, m.millSourcePath / 'tut)
+ t(eval)
+ }
+
+ def tests: Tests = Tests {
+ 'tut - {
+ 'createOutputFile - workspaceTest(TutTest) { eval =>
+ val expectedPath =
+ eval.outPath / 'tutTargetDirectory / 'dest / "TutExample.md"
+
+ val expected =
+ """
+ |```scala
+ |scala> 1 + 1
+ |res0: Int = 2
+ |```
+ |
+ """.trim.stripMargin
+
+ val Right((result, evalCount)) = eval.apply(TutTest.tut)
+
+ assert(
+ exists(expectedPath) &&
+ read! expectedPath == expected
+ )
+ }
+
+ 'supportCustomSettings - workspaceTest(TutCustomTest) { eval =>
+ val defaultPath =
+ eval.outPath / 'tutTargetDirectory / 'dest / "TutExample.md"
+ val expectedPath =
+ TutCustomTest.millSourcePath / "TutExample.md"
+
+ val expected =
+ """
+ |```scala
+ |scala> 1 + 1
+ |res0: Int = 2
+ |```
+ |
+ """.trim.stripMargin
+
+ val Right((result, evalCount)) = eval.apply(TutCustomTest.tut)
+
+ assert(
+ !exists(defaultPath) &&
+ exists(expectedPath) &&
+ read! expectedPath == expected
+ )
+ }
+
+ 'supportUsingLibraries - workspaceTest(TutLibrariesTest, resourcePath = resourcePathWithLibraries) { eval =>
+ val expectedPath =
+ eval.outPath / 'tutTargetDirectory / 'dest / "TutWithLibraries.md"
+
+ val expected =
+ """
+ |```scala
+ |import cats._
+ |import cats.arrow.FunctionK
+ |import cats.implicits._
+ |```
+ |
+ |```scala
+ |scala> List(1, 2, 3).combineAll
+ |res0: Int = 6
+ |
+ |scala> λ[FunctionK[List, Option]](_.headOption)(List(1, 2 ,3))
+ |res1: Option[Int] = Some(1)
+ |```
+ |
+ """.trim.stripMargin
+
+ val Right(_) = eval.apply(TutLibrariesTest.tut)
+
+ assert(
+ exists(expectedPath) &&
+ read! expectedPath == expected
+ )
+ }
+ }
+ }
+}
diff --git a/contrib/tut/test/tut-with-libraries/TutWithLibraries.md b/contrib/tut/test/tut-with-libraries/TutWithLibraries.md
new file mode 100644
index 00000000..7df1e703
--- /dev/null
+++ b/contrib/tut/test/tut-with-libraries/TutWithLibraries.md
@@ -0,0 +1,10 @@
+```tut:silent
+import cats._
+import cats.arrow.FunctionK
+import cats.implicits._
+```
+
+```tut
+List(1, 2, 3).combineAll
+λ[FunctionK[List, Option]](_.headOption)(List(1, 2 ,3))
+```
diff --git a/contrib/tut/test/tut/TutExample.md b/contrib/tut/test/tut/TutExample.md
new file mode 100644
index 00000000..c149fbc6
--- /dev/null
+++ b/contrib/tut/test/tut/TutExample.md
@@ -0,0 +1,3 @@
+```tut
+1 + 1
+```
diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md
index 4ddf097a..cd02f2c2 100644
--- a/docs/pages/9 - Contrib Modules.md
+++ b/docs/pages/9 - Contrib Modules.md
@@ -95,6 +95,62 @@ object project extends ScalaModule {
}
```
+### Tut
+
+This module allows [Tut](https://tpolecat.github.io/tut) to be used in Mill builds. Tut is a documentation tool which compiles and evaluates Scala code in documentation files and provides various options for configuring how the results will be displayed in the compiled documentation.
+
+To declare a module that uses Tut you can extend the `mill.contrib.tut.TutModule` trait when defining your module.
+
+This creates a Scala module which compiles markdown, HTML and `.txt` files in the `tut` folder of the module with Tut.
+
+By default the resulting documents are simply placed in the Mill build output folder but they can be placed elsewhere by overriding the `tutTargetDirectory` task.
+
+```scala
+// build.sc
+import mill._, scalalib._, contrib.tut.__
+
+object example extends TutModule {
+ def scalaVersion = "2.12.6"
+ def tutVersion = "0.6.7"
+}
+```
+
+This defines a project with the following layout:
+
+```
+build.sc
+example/
+ src/
+ tut/
+ resources/
+```
+
+In order to compile documentation we can execute the `tut` task in the module:
+
+```
+sh> mill example.tut
+```
+
+#### Configuration options
+
+* tutSourceDirectory - This task determines where documentation files must be placed in order to be compiled with Tut. By default this is the `tut` folder at the root of the module.
+
+* tutTargetDirectory - A task which determines where the compiled documentation files will be placed. By default this is simply the Mill build's output folder for the `tutTargetDirectory` task but this can be reconfigured so that documentation goes to the root of the module (e.g. `millSourcePath`) or to a dedicated folder (e.g. `millSourcePath / 'docs`)
+
+* tutClasspath - A task which determines what classpath is used when compiling documentation. By default this is configured to use the same inputs as the `runClasspath`, except for using `tutIvyDeps` rather than the module's `ivyDeps`.
+
+* tutScalacPluginIvyDeps - A task which determines the scalac plugins which will be used when compiling code examples with Tut. The default is to use the `scalacPluginIvyDeps` for the module.
+
+* tutNameFilter - A `scala.util.matching.Regex` task which will be used to determine which files should be compiled with tut. The default pattern is as follows: `.*\.(md|markdown|txt|htm|html)`.
+
+* tutScalacOptions - The scalac options which will be used when compiling code examples with Tut. The default is to use the `scalacOptions` for the module but filtering out options which are problematic in the REPL, e.g. `-Xfatal-warnings`, `-Ywarn-unused-imports`.
+
+* tutVersion - The version of Tut to use.
+
+* tutIvyDeps - A task which determines how to fetch the Tut jar file and all of the dependencies required to compile documentation for the module and returns the resulting files.
+
+* tutPluginJars - A task which performs the dependency resolution for the scalac plugins to be used with Tut.
+
### Twirl
Twirl templates support.
diff --git a/main/core/src/mill/util/JsonFormatters.scala b/main/core/src/mill/util/JsonFormatters.scala
index f92941f7..2728d94d 100644
--- a/main/core/src/mill/util/JsonFormatters.scala
+++ b/main/core/src/mill/util/JsonFormatters.scala
@@ -3,6 +3,7 @@ package mill.util
import ammonite.ops.{Bytes, Path}
import upickle.Js
import upickle.default.{ReadWriter => RW}
+import scala.util.matching.Regex
object JsonFormatters extends JsonFormatters
trait JsonFormatters {
implicit val pathReadWrite: RW[ammonite.ops.Path] = upickle.default.readwriter[String]
@@ -11,6 +12,12 @@ trait JsonFormatters {
Path(_)
)
+ implicit val regexReadWrite: RW[Regex] = upickle.default.readwriter[String]
+ .bimap[Regex](
+ _.pattern.toString,
+ _.r
+ )
+
implicit val bytesReadWrite: RW[Bytes] = upickle.default.readwriter[String]
.bimap(
o => javax.xml.bind.DatatypeConverter.printBase64Binary(o.array),