summaryrefslogtreecommitdiff
path: root/page
diff options
context:
space:
mode:
Diffstat (limited to 'page')
-rw-r--r--page/common-project-layouts.html355
-rw-r--r--page/configuring-mill.html447
-rw-r--r--page/contrib-modules.html649
-rw-r--r--page/cross-builds.html220
-rw-r--r--page/extending-mill.html210
-rw-r--r--page/mill-internals.html264
-rw-r--r--page/modules.html221
-rw-r--r--page/tasks.html324
-rw-r--r--page/thirdparty-modules.html351
9 files changed, 3041 insertions, 0 deletions
diff --git a/page/common-project-layouts.html b/page/common-project-layouts.html
new file mode 100644
index 00000000..d816d363
--- /dev/null
+++ b/page/common-project-layouts.html
@@ -0,0 +1,355 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Common Project Layouts</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#common-project-layouts">Common Project Layouts</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#java-project-with-test-suite">Java Project with Test Suite</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#cross-scala-version-modules">Cross Scala-Version Modules</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#scalajs-modules">Scala.js Modules</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#scala-native-modules">Scala Native Modules</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#sbt-compatible-modules">SBT-Compatible Modules</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#sbt-compatible-cross-scala-version-modules">SBT-Compatible Cross Scala-Version Modules</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#publishing">Publishing</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#example-builds">Example Builds</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#acyclic">Acyclic</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#better-files">Better-Files</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#jawn">Jawn</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#upickle">Upickle</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#ammonite">Ammonite</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Common Project Layouts</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="configuring-mill.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Configuring Mill</a><a href="tasks.html">Tasks <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><h2 id="common-project-layouts" class="Styles-hoverBox">Common Project Layouts<a href="#common-project-layouts" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Earlier, we have shown how to work with the Mill default Scala module layout. Here we will explore some other common project layouts that you may want in your Scala build:</p><h3 id="java-project-with-test-suite" class="Styles-hoverBox">Java Project with Test Suite<a href="#java-project-with-test-suite" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">trait JUnitTests extends TestModule {
+ def testFrameworks = Seq(&quot;com.novocode.junit.JUnitFramework&quot;)
+ def ivyDeps = Agg(ivy&quot;com.novocode:junit-interface:0.11&quot;)
+}
+
+object core extends JavaModule {
+ object test extends Tests with JUnitTests
+}
+object app extends JavaModule {
+ def moduleDeps = Seq(core)
+ object test extends Tests with JUnitTests
+}
+</code></pre>
+<p>This build is a two-module Java project with junit test suites. It expects the following filesystem layout:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">build.sc
+app/
+ src/hello/
+ Main.java
+ test/src/hello/
+ MyAppTests.java
+core/
+ src/hello/
+ Core.java
+ test/src/hello/
+ MyCoreTests.java
+</code></pre>
+<p>You can then run the junit tests using <code>mill app.test</code> or <code>mill core.test</code>, and configure which exact tests you want to run using the flags defined on the <a href="https://github.com/sbt/junit-interface#junit-interface">JUnit Test Interface</a>.</p>
+<p>For a more more complex, real-world example of a Java build, check out our example build for the popular <a href="https://github.com/ben-manes/caffeine">Caffeine</a> project:</p>
+<ul>
+ <li><a href="https://github.com/lihaoyi/mill/blob/master/integration/test/resources/caffeine/build.sc">Example Build</a></li>
+</ul><h3 id="cross-scala-version-modules" class="Styles-hoverBox">Cross Scala-Version Modules<a href="#cross-scala-version-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._
+import mill.scalalib._
+object foo extends Cross[FooModule](&quot;2.10.6&quot;, &quot;2.11.11&quot;, &quot;2.12.4&quot;)
+class FooModule(val crossScalaVersion: String) extends CrossScalaModule {
+ ...
+ object test extends Tests {
+ ...
+ }
+}
+</code></pre>
+<p>Mill provides a <code>CrossScalaModule</code> template, which can be used with <code>Cross</code> to cross-build Scala modules across different versions of Scala. The default configuration for <code>CrossScalaModule</code> expects a filesystem layout as follows:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">build.sc
+foo/
+ src/
+ src-2.10/
+ src-2.11/
+ src-2.12/
+ test/
+ src/
+ src-2.10/
+ src-2.11/
+ src-2.12/
+</code></pre>
+<p>Code common to all Scala versions lives in <code>src</code>, while code specific to one version lives in <code>src-x.y</code>.</p><h3 id="scalajs-modules" class="Styles-hoverBox">Scala.js Modules<a href="#scalajs-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._
+import mill.scalajslib._
+
+object foo extends ScalaJSModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def scalaJSVersion = &quot;0.6.22&quot;
+}
+</code></pre>
+<p><code>ScalaJSModule</code> is a variant of <code>ScalaModule</code> that builds your code using Scala.js. In addition to the standard <code>foo.compile</code> and <code>foo.run</code> commands (the latter of which runs your code on Node.js, which must be pre-installed) <code>ScalaJSModule</code> also exposes the <code>foo.fastOpt</code> and <code>foo.fullOpt</code> tasks for generating the optimized Javascript file.</p><h3 id="scala-native-modules" class="Styles-hoverBox">Scala Native Modules<a href="#scala-native-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._, scalanativelib._
+
+object hello extends ScalaNativeModule {
+ def scalaVersion = &quot;2.11.12&quot;
+ def scalaNativeVersion = &quot;0.3.8&quot;
+ def logLevel = NativeLogLevel.Info // optional
+ def releaseMode = ReleaseMode.Debug // optional
+}
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
+├── build.sc
+└── hello
+ ├── src
+ │   └── hello
+ │   └── Hello.scala
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// hello/src/hello/Hello.scala
+package hello
+import scalatags.Text.all._
+object Hello{
+ def main(args: Array[String]): Unit = {
+ println(&quot;Hello! &quot; + args.toList)
+ println(div(&quot;one&quot;))
+ }
+}
+</code></pre>
+<p>The normal commands <code>mill hello.compile</code>, <code>mill hello.run</code>, all work. If you want to build a standalone executable, you can use <code>mill show hello.nativeLink</code> to create it.</p>
+<p><code>ScalaNativeModule</code> builds scala sources to executable binaries using <a href="http://www.scala-native.org">Scala Native</a>. You will need to have the <a href="http://www.scala-native.org/en/latest/user/setup.html">relevant parts</a> of the LLVM toolchain installed on your system. Optimized binaries can be built by setting <code>releaseMode</code> (see above) and more verbose logging can be enabled using <code>logLevel</code>. Currently two test frameworks are supported <a href="https://github.com/lihaoyi/utest">utest</a> and <a href="http://www.scalatest.org/">scalatest</a>. Support for <a href="https://www.scalacheck.org/">scalacheck</a> should be possible when the relevant artifacts have been published for scala native.</p>
+<p>Here's a slightly larger example, demonstrating how to use third party dependencies (note the two sets of double-colons <code>::</code> necessary) and a test suite:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._, scalanativelib._
+
+object hello extends ScalaNativeModule {
+ def scalaNativeVersion = &quot;0.3.8&quot;
+ def scalaVersion = &quot;2.11.12&quot;
+ def ivyDeps = Agg(ivy&quot;com.lihaoyi::scalatags::0.6.7&quot;)
+ object test extends Tests{
+ def ivyDeps = Agg(ivy&quot;com.lihaoyi::utest::0.6.3&quot;)
+ def testFrameworks = Seq(&quot;utest.runner.Framework&quot;)
+ }
+}
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
+├── build.sc
+└── hello
+ ├── src
+ │   └── hello
+ │   └── Hello.scala
+ └── test
+ └── src
+ └── HelloTests.scala
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// hello/test/src/HelloTests.scala
+package hello
+import utest._
+import scalatags.Text.all._
+object HelloTests extends TestSuite{
+ val tests = Tests{
+ &#39;pass - {
+ assert(div(&quot;1&quot;).toString == &quot;&lt;div&gt;1&lt;/div&gt;&quot;)
+ }
+ &#39;fail - {
+ assert(123 == 1243)
+ }
+ }
+}
+</code></pre>
+<p>The same <code>mill hello.compile</code> or <code>mill hello.run</code> still work, as does `<code>mill
+hello.test</code> to run the test suite defined here.</p><h3 id="sbt-compatible-modules" class="Styles-hoverBox">SBT-Compatible Modules<a href="#sbt-compatible-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._
+import mill.scalalib._
+
+object foo extends SbtModule {
+ def scalaVersion = &quot;2.12.4&quot;
+}
+</code></pre>
+<p>These are basically the same as normal <code>ScalaModule</code>s, but configured to follow the SBT project layout:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">build.sc
+foo/
+ src/
+ main/
+ scala/
+ test/
+ scala/
+</code></pre>
+<p>Useful if you want to migrate an existing project built with SBT without having to re-organize all your files</p><h3 id="sbt-compatible-cross-scala-version-modules" class="Styles-hoverBox">SBT-Compatible Cross Scala-Version Modules<a href="#sbt-compatible-cross-scala-version-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._
+import mill.scalalib._
+object foo extends Cross[FooModule](&quot;2.10.6&quot;, &quot;2.11.11&quot;, &quot;2.12.4&quot;)
+class FooModule(val crossScalaVersion: String) extends CrossSbtModule {
+ ...
+ object test extends Tests {
+ ...
+ }
+}
+</code></pre>
+<p>A <code>CrossSbtModule</code> is a version of <code>CrossScalaModule</code> configured with the SBT project layout:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">build.sc
+foo/
+ src/
+ main/
+ scala/
+ scala-2.10/
+ scala-2.11/
+ scala-2.12/
+ test/
+ scala/
+ scala-2.10/
+ scala-2.11/
+ scala-2.12/
+</code></pre><h3 id="publishing" class="Styles-hoverBox">Publishing<a href="#publishing" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._
+import mill.scalalib._
+import mill.scalalib.publish._
+object foo extends ScalaModule with PublishModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def publishVersion = &quot;0.0.1&quot;
+ def pomSettings = PomSettings(
+ description = &quot;My first library&quot;,
+ organization = &quot;com.lihaoyi&quot;,
+ url = &quot;https://github.com/lihaoyi/mill&quot;,
+ licenses = Seq(License.MIT),
+ versionControl = VersionControl.github(&quot;lihaoyi&quot;, &quot;mill&quot;),
+ developers = Seq(
+ Developer(&quot;lihaoyi&quot;, &quot;Li Haoyi&quot;,&quot;https://github.com/lihaoyi&quot;)
+ )
+ )
+}
+</code></pre>
+<p>You can make a module publishable by extending <code>PublishModule</code>.</p>
+<p><code>PublishModule</code> then needs you to define a <code>publishVersion</code> and <code>pomSettings</code>. The <code>artifactName</code> defaults to the name of your module (in this case <code>foo</code>) but can be overriden. The <code>organization</code> is defined in <code>pomSettings</code>.</p>
+<p>Once you've mixed in <code>PublishModule</code>, you can publish your libraries to maven central via:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill mill.scalalib.PublishModule/publishAll \
+ lihaoyi:$SONATYPE_PASSWORD \
+ $GPG_PASSWORD \
+ foo.publishArtifacts
+</code></pre>
+<p>This uploads them to <code>oss.sonatype.org</code> where you can log-in and stage/release them manually. You can also pass in the <code>--release true</code> flag to perform the staging/release automatically:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill mill.scalalib.PublishModule/publishAll \
+ lihaoyi:$SONATYPE_PASSWORD \
+ $GPG_PASSWORD \
+ foo.publishArtifacts \
+ --release true
+</code></pre>
+<p>If you want to publish/release multiple modules, you can use the <code>_</code> or <code>__</code> wildcard syntax:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill mill.scalalib.PublishModule/publishAll \
+ lihaoyi:$SONATYPE_PASSWORD \
+ $GPG_PASSWORD \
+ __.publishArtifacts \
+ --release true
+</code></pre><h2 id="example-builds" class="Styles-hoverBox">Example Builds<a href="#example-builds" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Mill comes bundled with example builds for existing open-source projects, as integration tests and examples:</p><h3 id="acyclic" class="Styles-hoverBox">Acyclic<a href="#acyclic" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><a href="https://github.com/lihaoyi/mill/blob/master/integration/test/resources/acyclic/build.sc#L1">Mill Build</a></li>
+</ul>
+<p>A small single-module cross-build, with few sources, minimal dependencies, and wired up for publishing to Maven Central.</p><h3 id="better-files" class="Styles-hoverBox">Better-Files<a href="#better-files" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><a href="https://github.com/lihaoyi/mill/blob/master/integration/test/resources/better-files/build.sc#L1">Mill Build</a></li>
+</ul>
+<p>A collection of small modules compiled for a single Scala version.</p>
+<p>Also demonstrates how to define shared configuration in a <code>trait</code>, enable Scala compiler flags, and download artifacts as part of the build.</p><h3 id="jawn" class="Styles-hoverBox">Jawn<a href="#jawn" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><a href="https://github.com/lihaoyi/mill/blob/master/integration/test/resources/jawn/build.sc#L1">Mill Build</a></li>
+</ul>
+<p>A collection of relatively small modules, all cross-built across the same few versions of Scala.</p><h3 id="upickle" class="Styles-hoverBox">Upickle<a href="#upickle" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><a href="https://github.com/lihaoyi/mill/blob/master/integration/test/resources/upickle/build.sc#L1">Mill Build</a></li>
+</ul>
+<p>A single cross-platform Scala.js/Scala-JVM module cross-built against multiple versions of Scala, including the setup necessary for publishing to Maven Central.</p><h3 id="ammonite" class="Styles-hoverBox">Ammonite<a href="#ammonite" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><a href="https://github.com/lihaoyi/mill/blob/master/integration/test/resources/ammonite/build.sc#L1">Mill Build</a></li>
+</ul>
+<p>A relatively complex build with numerous submodules, some cross-built across Scala major versions while others are cross-built against Scala minor versions.</p>
+<p>Also demonstrates how to pass one module's compiled artifacts to the <code>run</code>/<code>test</code> commands of another, via their <code>forkEnv</code>.</p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="configuring-mill.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Configuring Mill</a><a href="tasks.html">Tasks <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/configuring-mill.html b/page/configuring-mill.html
new file mode 100644
index 00000000..70cff6f3
--- /dev/null
+++ b/page/configuring-mill.html
@@ -0,0 +1,447 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Configuring Mill</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#compilation--execution-flags">Compilation &amp; Execution Flags</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#adding-ivy-dependencies">Adding Ivy Dependencies</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#adding-a-test-suite">Adding a Test Suite</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#custom-test-frameworks">Custom Test Frameworks</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#scala-compiler-plugins">Scala Compiler Plugins</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#reformatting-your-code">Reformatting your code</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#common-configuration">Common Configuration</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#global-configuration">Global configuration</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#custom-tasks">Custom Tasks</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#custom-modules">Custom Modules</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#moduletask-names">Module/Task Names</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#overriding-tasks">Overriding Tasks</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#unmanaged-jars">Unmanaged Jars</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#defining-a-main-class">Defining a Main Class</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#mergeexclude-files-from-assembly">Merge/exclude files from assembly</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#downloading-non-maven-jars">Downloading Non-Maven Jars</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Configuring Mill</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="../index.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Intro to Mill</a><a href="common-project-layouts.html">Common Project Layouts <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><p>You can configure your Mill build in a number of ways:</p><h2 id="compilation--execution-flags" class="Styles-hoverBox">Compilation &amp; Execution Flags<a href="#compilation--execution-flags" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+
+ def scalacOptions = Seq(&quot;-Ydelambdafy:inline&quot;)
+
+ def forkArgs = Seq(&quot;-Xmx4g&quot;)
+
+ def forkEnv = Map(&quot;HELLO_MY_ENV_VAR&quot; -&gt; &quot;WORLD&quot;)
+}
+</code></pre>
+<p>You can pass flags to the Scala compiler via <code>scalacOptions</code>. By default, <code>foo.run</code> runs the compiled code in a subprocess, and you can pass in JVM flags via <code>forkArgs</code> or environment-variables via <code>forkEnv</code>.</p>
+<p>You can also run your code via</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill foo.runLocal
+</code></pre>
+<p>Which runs it in-process within an isolated classloader. This may be faster since you avoid the JVM startup, but does not support <code>forkArgs</code> or <code>forkEnv</code>.</p>
+<p>If you want to pass main-method arguments to <code>run</code> or <code>runLocal</code>, simply pass them after the <code>foo.run</code>/<code>foo.runLocal</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill foo.run arg1 arg2 arg3
+mill foo.runLocal arg1 arg2 arg3
+</code></pre><h2 id="adding-ivy-dependencies" class="Styles-hoverBox">Adding Ivy Dependencies<a href="#adding-ivy-dependencies" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def ivyDeps = Agg(
+ ivy&quot;com.lihaoyi::upickle:0.5.1&quot;,
+ ivy&quot;com.lihaoyi::pprint:0.5.2&quot;,
+ ivy&quot;com.lihaoyi::fansi:0.2.4&quot;,
+ ivy&quot;${scalaOrganization()}:scala-reflect:${scalaVersion()}&quot;
+ )
+}
+</code></pre>
+<p>You can define the <code>ivyDeps</code> field to add ivy dependencies to your module. The <code>ivy&quot;com.lihaoyi::upickle:0.5.1&quot;</code> syntax (with <code>::</code>) represents Scala dependencies; for Java dependencies you would use a single <code>:</code> e.g. <code>ivy&quot;com.lihaoyi:upickle:0.5.1&quot;</code>. If you have dependencies cross-published against the full Scala version (eg. <code>2.12.4</code> instead of just <code>2.12</code>), you can use <code>:::</code> as in <code>ivy&quot;org.scalamacros:::paradise:2.1.1&quot;</code>.</p>
+<p>To select the test-jars from a dependency use the following syntax: <code>ivy&quot;org.apache.spark::spark-sql:2.4.0;classifier=tests</code>.</p>
+<p>By default these are resolved from maven central, but you can add your own resolvers by overriding the <code>repositories</code> definition in the module:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import coursier.maven.MavenRepository
+
+def repositories = super.repositories ++ Seq(
+ MavenRepository(&quot;https://oss.sonatype.org/content/repositories/releases&quot;)
+)
+</code></pre>
+<p>To add custom resolvers to the initial bootstrap of the build, you can create a custom <code>ZincWorkerModule</code>, and override the <code>zincWorker</code> method in your <code>ScalaModule</code> by pointing it to that custom object:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import coursier.maven.MavenRepository
+
+object CustomZincWorkerModule extends ZincWorkerModule {
+ def repositories() = super.repositories ++ Seq(
+ MavenRepository(&quot;https://oss.sonatype.org/content/repositories/releases&quot;)
+ )
+}
+
+object YourBuild extends ScalaModule {
+ def zincWorker = CustomZincWorkerModule
+ // ... rest of your build definitions
+}
+</code></pre><h2 id="adding-a-test-suite" class="Styles-hoverBox">Adding a Test Suite<a href="#adding-a-test-suite" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+
+ object test extends Tests {
+ def ivyDeps = Agg(ivy&quot;com.lihaoyi::utest:0.6.0&quot;)
+ def testFrameworks = Seq(&quot;utest.runner.Framework&quot;)
+ }
+}
+</code></pre>
+<p>You can define a test suite by creating a nested module extending <code>Tests</code>, and specifying the ivy coordinates and name of your test framework. This expects the tests to be laid out as follows:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">build.sc
+foo/
+ src/
+ Main.scala
+ resources/
+ ...
+ test/
+ src/
+ MainTest.scala
+ resources/
+ ...
+out/
+ foo/
+ ...
+ test/
+ ...
+</code></pre>
+<p>The above example can be run via</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill foo.test
+</code></pre>
+<p>By default, tests are run in a subprocess, and <code>forkArg</code> and <code>forkEnv</code> can be overriden to pass JVM flags &amp; environment variables. You can also use</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill foo.test.testLocal
+</code></pre>
+<p>To run tests in-process in an isolated classloader.</p>
+<p>If you want to pass any arguments to the test framework, simply put them after <code>foo.test</code> in the command line. e.g. <a href="https://github.com/lihaoyi/utest">uTest</a> lets you pass in a selector to decide which test to run, which in Mill would be:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill foo.test foo.MyTestSuite.testCaseName
+</code></pre>
+<p>You can define multiple test suites if you want, e.g.:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+
+ object test extends Tests {
+ def ivyDeps = Agg(ivy&quot;com.lihaoyi::utest:0.6.0&quot;)
+ def testFrameworks = Seq(&quot;utest.runner.Framework&quot;)
+ }
+ object integration extends Tests {
+ def ivyDeps = Agg(ivy&quot;com.lihaoyi::utest:0.6.0&quot;)
+ def testFrameworks = Seq(&quot;utest.runner.Framework&quot;)
+ }
+}
+</code></pre>
+<p>Each of which will expect their sources to be in their respective <code>foo/test</code> and <code>foo/integration</code> folder.</p>
+<p><code>Tests</code> modules are <code>ScalaModule</code>s like any other, and all the same configuration options apply.</p><h2 id="custom-test-frameworks" class="Styles-hoverBox">Custom Test Frameworks<a href="#custom-test-frameworks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def ivyDeps = Agg(ivy&quot;org.scalatest::scalatest:3.0.4&quot;)
+ def testFrameworks = Seq(&quot;org.scalatest.tools.Framework&quot;)
+}
+</code></pre>
+<p>Integrating with test frameworks like Scalatest is simply a matter of adding it to <code>ivyDeps</code> and specifying the <code>testFrameworks</code> you want to use. After that you can <a href="#adding-a-test-suite">add a test suite</a> and <code>mill foo.test</code> as usual, passing args to the test suite via <code>mill foo.test arg1 arg2 arg3</code></p><h2 id="scala-compiler-plugins" class="Styles-hoverBox">Scala Compiler Plugins<a href="#scala-compiler-plugins" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+
+ def compileIvyDeps = Agg(ivy&quot;com.lihaoyi::acyclic:0.1.7&quot;)
+ def scalacOptions = Seq(&quot;-P:acyclic:force&quot;)
+ def scalacPluginIvyDeps = Agg(ivy&quot;com.lihaoyi::acyclic:0.1.7&quot;)
+}
+</code></pre>
+<p>You can use Scala compiler plugins by setting <code>scalacPluginIvyDeps</code>. The above example also adds the plugin to <code>compileIvyDeps</code>, since that plugin's artifact is needed on the compilation classpath (though not at runtime).</p><h2 id="reformatting-your-code" class="Styles-hoverBox">Reformatting your code<a href="#reformatting-your-code" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Mill supports code formatting via <a href="https://scalameta.org/scalafmt/">scalafmt</a> out of the box.</p>
+<p>To have a formatting per-module you need to make your module extend <code>mill.scalalib.scalafmt.ScalafmtModule</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._, scalafmt._
+
+object foo extends ScalaModule with ScalafmtModule {
+ def scalaVersion = &quot;2.12.4&quot;
+}
+</code></pre>
+<p>Now you can reformat code with <code>mill foo.reformat</code> command.</p>
+<p>You can also reformat your project's code globally with <code>mill mill.scalalib.scalafmt.ScalafmtModule/reformatAll __.sources</code> command. It will reformat all sources that matches <code>__.sources</code> query.</p>
+<p>If you add a <code>.scalafmt.conf</code> file at the root of you project, it will be used to configure formatting. It can contain a <code>version</code> key to specify the scalafmt version used to format your code. See the <a href="https://scalameta.org/scalafmt/docs/configuration.html">scalafmt configuration documentation</a> for details.</p><h2 id="common-configuration" class="Styles-hoverBox">Common Configuration<a href="#common-configuration" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+trait CommonModule extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+}
+
+object foo extends CommonModule
+object bar extends CommonModule {
+ def moduleDeps = Seq(foo)
+}
+</code></pre>
+<p>You can extract out configuration common to multiple modules into a <code>trait</code> that those modules extend. This is useful for providing convenience &amp; ensuring consistent configuration: every module often has the same scala-version, uses the same testing framework, etc. and all that can be extracted out into the <code>trait</code>.</p><h2 id="global-configuration" class="Styles-hoverBox">Global configuration<a href="#global-configuration" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Mill builds on ammonite which allows you to <a href="http://ammonite.io/#ScriptPredef">define global configuration</a>. Depending on how you start mill 2 different files will be loaded. For interactive mode it's <code>~/.mill/ammonite/predef.sc</code> and from the command line it's <code>~/.mill/ammonite/predefScript.sc</code>. You might want to create a symlink from one to the other to avoid duplication.</p>
+<p>Example <code>~/.mill/ammonite/predef.sc</code></p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">val nexusUser = &quot;myuser&quot;
+val nexusPassword = &quot;mysecret&quot;
+</code></pre>
+<p>Everything declared in the above file will be available to any build you run.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala"> def repositories = super.repositories ++ Seq(
+ // login and pass are globally configured
+ MavenRepository(&quot;https://nexus.mycompany.com/repository/maven-releases&quot;, authentication = Some(coursier.core.Authentication(nexusUser, nexusPassword)))
+ )
+</code></pre><h2 id="custom-tasks" class="Styles-hoverBox">Custom Tasks<a href="#custom-tasks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+}
+
+def lineCount = T {
+
+ foo.sources().flatMap(ref =&gt; os.walk(ref.path)).filter(_.isFile).flatMap(read.lines).size
+}
+
+def printLineCount() = T.command {
+ println(lineCount())
+}
+</code></pre>
+<p>You can define new cached Targets using the <code>T {...}</code> syntax, depending on existing Targets e.g. <code>foo.sources</code> via the <code>foo.sources()</code> syntax to extract their current value, as shown in <code>lineCount</code> above. The return-type of a Target has to be JSON-serializable (using <a href="https://github.com/lihaoyi/upickle">uPickle</a>) and the Target is cached when first run until its inputs change (in this case, if someone edits the <code>foo.sources</code> files which live in <code>foo/src</code>. Cached Targets cannot take parameters.</p>
+<p>You can print the value of your custom target using <code>show</code>, e.g.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill show lineCount
+</code></pre>
+<p>You can define new un-cached Commands using the <code>T.command {...}</code> syntax. These are un-cached and re-evaluate every time you run them, but can take parameters. Their return type needs to be JSON-writable as well, or <code>(): Unit</code> if you want to return nothing.</p>
+<p>Your custom targets can depend on each other using the <code>def bar = T {... foo()
+...}</code> syntax, and you can create arbitrarily long chains of dependent targets. Mill will handle the re-evaluation and caching of the targets' output for you, and will provide you a <code>T.ctx().dest</code> folder for you to use as scratch space or to store files you want to return.</p>
+<p>Custom targets and commands can contain arbitrary code. Whether you want to download files (e.g. using <code>mill.modules.Util.download</code>), shell-out to Webpack to compile some Javascript, generate sources to feed into a compiler, or create some custom jar/zip assembly with the files you want (e.g. using <code>mill.modules.Jvm.createJar</code>), all of these can simply be custom targets with your code running in the <code>T {...}</code> block.</p><h2 id="custom-modules" class="Styles-hoverBox">Custom Modules<a href="#custom-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object qux extends Module {
+ object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ }
+ object bar extends ScalaModule {
+ def moduleDeps = Seq(foo)
+ def scalaVersion = &quot;2.12.4&quot;
+ }
+}
+</code></pre>
+<p>Not every Module needs to be a <code>ScalaModule</code>; sometimes you just want to group things together for neatness. In the above example, you can run <code>foo</code> and <code>bar</code> namespaced inside <code>qux</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill qux.foo.compile
+mill qux.bar.run
+</code></pre>
+<p>You can also define your own module traits, with their own set of custom tasks, to represent other things e.g. Javascript bundles, docker image building,:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+trait MySpecialModule extends Module {
+ ...
+}
+object foo extends MySpecialModule
+object bar extends MySpecialModule
+</code></pre><h2 id="moduletask-names" class="Styles-hoverBox">Module/Task Names<a href="#moduletask-names" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import mill.scalalib._
+
+object `hyphenated-module` extends Module {
+ def `hyphenated-target` = T{
+ println(&quot;This is a hyphenated target in a hyphenated module.&quot;)
+ }
+}
+
+object unhyphenatedModule extends Module {
+ def unhyphenated_target = T{
+ println(&quot;This is an unhyphenated target in an unhyphenated module.&quot;)
+ }
+ def unhyphenated_target2 = T{
+ println(&quot;This is the second unhyphenated target in an unhyphenated module.&quot;)
+ }
+}
+</code></pre>
+<p>Mill modules and tasks may be composed of any of the following characters types:</p>
+<ul>
+ <li>Alphanumeric (A-Z, a-z, and 0-9)</li>
+ <li>Underscore (_)</li>
+ <li>Hyphen (-)</li>
+</ul>
+<p>Due to Scala naming restrictions, module and task names with hyphens must be surrounded by back-ticks (`).</p>
+<p>Using hyphenated names at the command line is unaffected by these restrictions.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill hyphenated-module.hyphenated-target
+mill unhyphenatedModule.unhyphenated_target
+mill unhyphenatedModule.unhyphenated_target2
+</code></pre><h2 id="overriding-tasks" class="Styles-hoverBox">Overriding Tasks<a href="#overriding-tasks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def compile = T {
+ println(&quot;Compiling...&quot;)
+ super.compile()
+ }
+ def run(args: String*) = T.command {
+ println(&quot;Running...&quot; + args.mkString(&quot; &quot;))
+ super.run(args:_*)
+ }
+}
+</code></pre>
+<p>You can re-define targets and commands to override them, and use <code>super</code> if you want to refer to the originally defined task. The above example shows how to override <code>compile</code> and <code>run</code> to add additional logging messages, but you can also override <code>ScalaModule#generatedSources</code> to feed generated code to your compiler, <code>ScalaModule#prependShellScript</code> to make your assemblies executable, or <code>ScalaModule#console</code> to use the Ammonite REPL instead of the normal Scala REPL.</p>
+<p>In Mill builds the <code>override</code> keyword is optional.</p><h2 id="unmanaged-jars" class="Styles-hoverBox">Unmanaged Jars<a href="#unmanaged-jars" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def unmanagedClasspath = T {
+ if (!ammonite.ops.exists(millSourcePath / &quot;lib&quot;)) Agg()
+ else Agg.from(ammonite.ops.ls(millSourcePath / &quot;lib&quot;).map(PathRef(_)))
+ }
+}
+</code></pre>
+<p>You can override <code>unmanagedClasspath</code> to point it at any jars you place on the filesystem, e.g. in the above snippet any jars that happen to live in the <code>foo/lib/</code> folder.</p><h2 id="defining-a-main-class" class="Styles-hoverBox">Defining a Main Class<a href="#defining-a-main-class" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def mainClass = Some(&quot;foo.bar.Baz&quot;)
+}
+</code></pre>
+<p>Mill's <code>foo.run</code> by default will discover which main class to run from your compilation output, but if there is more than one or the main class comes from some library you can explicitly specify which one to use. This also adds the main class to your <code>foo.jar</code> and <code>foo.assembly</code> jars.</p><h2 id="mergeexclude-files-from-assembly" class="Styles-hoverBox">Merge/exclude files from assembly<a href="#mergeexclude-files-from-assembly" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>When you make a runnable jar of your project with <code>assembly</code> command, you may want to exclude some files from a final jar (like signature files, and manifest files from library jars), and merge duplicated files (for instance <code>reference.conf</code> files from library dependencies).</p>
+<p>By default mill excludes all <code>*.sf</code>, <code>*.dsa</code>, <code>*.rsa</code>, and <code>META-INF/MANIFEST.MF</code> files from assembly, and concatenates all <code>reference.conf</code> files. You can also define your own merge/exclude rules.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+import mill.modules.Assembly._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def assemblyRules = Seq(
+ Rule.Append(&quot;application.conf&quot;), // all application.conf files will be concatenated into single file
+ Rule.AppendPattern(&quot;.*\\.conf&quot;), // all *.conf files will be concatenated into single file
+ Rule.ExcludePattern(&quot;*.temp&quot;) // all *.temp files will be excluded from a final jar
+ )
+}
+</code></pre>
+<p>To exclude Scala library from assembly</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+import mill.modules.Assembly._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+
+ def scalaLibraryIvyDeps = T { Agg.empty }
+}
+</code></pre><h2 id="downloading-non-maven-jars" class="Styles-hoverBox">Downloading Non-Maven Jars<a href="#downloading-non-maven-jars" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, scalalib._
+
+object foo extends ScalaModule {
+ def scalaVersion = &quot;2.12.4&quot;
+ def unmanagedClasspath = Agg(
+ mill.modules.Util.download(
+ &quot;https://github.com/williamfiset/FastJavaIO/releases/download/v1.0/fastjavaio.jar&quot;,
+ &quot;fastjavaio.jar&quot;
+ )
+ )
+}
+</code></pre>
+<p>You can also override <code>unmanagedClasspath</code> to point it at jars that you want to download from arbitrary URLs. Note that targets like <code>unmanagedClasspath</code> are cached, so your jar is downloaded only once and re-used indefinitely after that.</p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="../index.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Intro to Mill</a><a href="common-project-layouts.html">Common Project Layouts <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/contrib-modules.html b/page/contrib-modules.html
new file mode 100644
index 00000000..22abad5e
--- /dev/null
+++ b/page/contrib-modules.html
@@ -0,0 +1,649 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Contrib Modules</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#bloop">Bloop</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#mix-in">Mix-in</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#note-regarding-metals">Note regarding metals</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#note-regarding-current-mill-support-in-bloop">Note regarding current mill support in bloop</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#buildinfo">BuildInfo</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration-options">Configuration options</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#docker">Docker</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration">Configuration</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#flyway">Flyway</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#play-framework">Play Framework</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-the-plugin">Using the plugin</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-playmodule">Using PlayModule</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-playapimodule">Using PlayApiModule</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#play-configuration-options">Play configuration options</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#additional-play-libraries">Additional play libraries</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#commands-equivalence">Commands equivalence</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-singlemodule">Using SingleModule</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#scalapb">ScalaPB</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration-options">Configuration options</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#scoverage">Scoverage</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#testng">TestNG</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#tut">Tut</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration-options">Configuration options</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#twirl">Twirl</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#twirl-configuration-options">Twirl configuration options</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#details">Details</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#example">Example</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Contrib Modules</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="mill-internals.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Mill Internals</a><a href="thirdparty-modules.html">Thirdparty Modules <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><p>The plugins in this section are developed/maintained in the mill git tree.</p>
+<p>When using one of these, it is important that the versions you load match your mill version. To facilitate this, Mill will automatically replace the <code>$MILL_VERSION</code> literal in your ivy imports with the correct value.</p>
+<p>For instance :</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION`
+</code></pre><h2 id="bloop" class="Styles-hoverBox">Bloop<a href="#bloop" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>This plugin generates <a href="https://scalacenter.github.io/bloop/">bloop</a> configuration from your build file, which lets you use the bloop CLI for compiling, and makes your scala code editable in <a href="https://scalameta.org/metals/">Metals</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc (or any other .sc file it depends on, including predef)
+import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION`
+</code></pre>
+<p>Then in your terminal :</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">&gt; mill mill.contrib.Bloop/install
+</code></pre>
+<p>It generate correct bloop config for any <code>JavaModule</code>, <code>ScalaModule</code>, <code>ScalaJsModule</code> or <code>ScalaNativeModule</code> under the <code>.bloop</code> folder</p><h3 id="mix-in" class="Styles-hoverBox">Mix-in<a href="#mix-in" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>You can mix-in the <code>Bloop.Module</code> trait with any JavaModule to quickly access the deserialised configuration for that particular module:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import mill.scalalib._
+import mill.contrib.Bloop
+
+object MyModule extends ScalaModule with Bloop.Module {
+ def myTask = T { bloop.config() }
+}
+</code></pre><h3 id="note-regarding-metals" class="Styles-hoverBox">Note regarding metals<a href="#note-regarding-metals" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Generating the bloop config should be enough for metals to pick it up and for features to start working in vscode (or the bunch of other editors metals supports). However, note that this applies only to your project sources. Your mill/ammonite related <code>.sc</code> files are not yet supported by metals.</p>
+<p>The generated bloop config references the semanticDB compiler plugin required by metals to function. If need be, the version of semanticDB can be overriden by extending <code>mill.contrib.bloop.BloopImpl</code> in your own space.</p><h3 id="note-regarding-current-mill-support-in-bloop" class="Styles-hoverBox">Note regarding current mill support in bloop<a href="#note-regarding-current-mill-support-in-bloop" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The mill-bloop integration currently present in the <a href="https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10">bloop codebase</a> will be deprecated in favour of this implementation.</p><h2 id="buildinfo" class="Styles-hoverBox">BuildInfo<a href="#buildinfo" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Generate scala code from your buildfile. This plugin generates a single object containing information from your build.</p>
+<p>To declare a module that uses BuildInfo you must extend the <code>mill.contrib.buildinfo.BuildInfo</code> trait when defining your module.</p>
+<p>Quickstart:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import $ivy.`com.lihaoyi::mill-contrib-buildinfo:$MILL_VERSION`
+import mill.contrib.buildinfo.BuildInfo
+
+object project extends BuildInfo {
+ val name = &quot;poject-name&quot;
+ def buildInfoMembers: T[Map[String, String]] = T {
+ Map(
+ &quot;name&quot; -&gt; name),
+ &quot;scalaVersion&quot; -&gt; scalaVersion()
+ )
+ }
+}
+</code></pre><h3 id="configuration-options" class="Styles-hoverBox">Configuration options<a href="#configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li>
+ <p><code>def buildInfoMembers: T[Map[String, String]]</code> The map containing all member names and values for the generated info object.</p></li>
+ <li>
+ <p><code>def buildInfoObjectName: String</code>, default: <code>BuildInfo</code> The name of the object which contains all the members from <code>buildInfoMembers</code>.</p></li>
+ <li>
+ <p><code>def buildInfoPackageName: Option[String]</code>, default: <code>None</code> The package name of the object.</p></li>
+</ul><h2 id="docker" class="Styles-hoverBox">Docker<a href="#docker" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Automatically build docker images from your mill project.</p>
+<p>Requires the docker CLI to be installed.</p>
+<p>In the simplest configuration just extend <code>DockerModule</code> and declare a <code>DockerConfig</code> object.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._
+
+import ivy`com.lihaoyi::mill-contrib-docker:VERSION`
+import contrib.docker.DockerModule
+
+object foo extends JavaModule with DockerModule {
+ object docker extends DockerConfig
+}
+</code></pre>
+<p>Then</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">$ mill foo.docker.build
+$ docker run foo
+</code></pre><h3 id="configuration" class="Styles-hoverBox">Configuration<a href="#configuration" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Configure the image by overriding tasks in the <code>DockerConfig</code> object</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object docker extends DockerConfig {
+ // Override tags to set the output image name
+ def tags = List(&quot;aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository&quot;)
+
+ def baseImage = &quot;openjdk:11&quot;
+
+ // Configure whether the docker build should check the remote registry for a new version of the base image before building.
+ // By default this is true if the base image is using a latest tag
+ def pullBaseImage = true
+}
+</code></pre>
+<p>Run mill in interactive mode to see the docker client output, like <code>mill -i foo.docker.build</code>.</p><h2 id="flyway" class="Styles-hoverBox">Flyway<a href="#flyway" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Enables you to configure and run <a href="https://flywaydb.org/">Flyway</a> commands from your mill build file. The flyway module currently supports the most common flyway use cases with file based migrations.</p>
+<p>Configure flyway by overriding settings in your module. For example</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+
+import mill._, scalalib._
+
+import ivy`com.lihaoyi::mill-contrib-flyway:$MILL_VERSION`
+import contrib.flyway.FlywayModule
+
+object foo extends ScalaModule with FlywayModule {
+ def scalaVersion = &quot;2.12.8&quot;
+
+ //region flyway
+ def flywayUrl = &quot;jdbc:postgresql:myDb&quot; // required
+ def flywayDriverDeps = Agg(ivy&quot;org.postgresql:postgresql:42.2.5&quot;) // required
+ def flywayUser = &quot;postgres&quot; // optional
+ // def flywayPassword = &quot;&quot; // optional
+ //endregion
+}
+</code></pre>
+<p>Flyway will look for migration files in <code>db/migration</code> in all resources folders by default. This should work regardless of if you are using a mill or sbt project layout.</p>
+<p>You can then run common flyway commands like</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">mill foo.flywayClean
+mill foo.flywayInfo
+mill foo.flywayMigrate
+</code></pre>
+<blockquote>
+ <p>REMINDER: You should never hard-code credentials or check them into a version control system. You should write some code to populate the settings for flyway instead. For example <code>def flywayPassword = T.input(T.ctx().env(&quot;FLYWAY_PASSWORD&quot;))</code></p>
+</blockquote><h2 id="play-framework" class="Styles-hoverBox">Play Framework<a href="#play-framework" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>This module adds basic Play Framework support to mill:</p>
+<ul>
+ <li>configures mill for Play default directory layout,</li>
+ <li>integrates the Play routes compiler,</li>
+ <li>provides helpers for commonly used framework libraries,</li>
+ <li>optionally: integrates the Twirl template engine,</li>
+ <li>optionally: configures mill for single module play applications.</li>
+</ul>
+<p>There is no specific Play Java support, building a Play Java application will require a bit of customization (mostly adding the proper dependencies).</p><h3 id="using-the-plugin" class="Styles-hoverBox">Using the plugin<a href="#using-the-plugin" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>There are 2 base modules and 2 helper traits in this plugin, all of which can be found in <code>mill.playlib</code>.</p>
+<p>The base modules:</p>
+<ul>
+ <li><code>PlayModule</code> applies the default Play configuration (layout, dependencies, routes compilation, Twirl compilation and Akka HTTP server)</li>
+ <li><code>PlayApiModule</code> applies the default Play configuration without <code>Twirl</code> templating. This is useful if your Play app is a pure API server or if you want to use a different templating engine.</li>
+</ul>
+<p>The two helper traits:</p>
+<ul>
+ <li><code>SingleModule</code> can be useful to configure mill for a single module Play application such as the <a href="https://github.com/playframework/play-scala-seed.g8">play-scala-seed project</a>. Mill is multi-module by default and requires a bit more configuration to have source, resource, and test directories at the top level alongside the <code>build.sc</code> file. This trait takes care of that (See <a href="#using-singlemodule">Using SingleModule</a> below).</li>
+ <li><code>RouterModule</code> allows you to use the Play router without the rest of the configuration (see <a href="#using-the-router-module-directly">Using the router module directly</a>.)</li>
+</ul><h3 id="using-playmodule" class="Styles-hoverBox">Using <code>PlayModule</code><a href="#using-playmodule" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>In order to use the <code>PlayModule</code> for your application, you need to provide the scala, Play and Twirl versions. You also need to define your own test object which extends the provided <code>PlayTests</code> trait.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+
+object core extends PlayModule {
+ //config
+ override def scalaVersion= T{&quot;2.12.8&quot;}
+ override def playVersion= T{&quot;2.7.0&quot;}
+ override def twirlVersion= T{&quot;1.4.0&quot;}
+
+ object test extends PlayTests
+}
+</code></pre>
+<p>Using the above definition, your build will be configured to use the default Play layout:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
+├── build.sc
+└── core
+ ├── app
+ │   ├── controllers
+ │   └── views
+ ├── conf
+ │   └── application.conf
+ │   └── routes
+ │   └── ...
+ ├── logs
+ ├── public
+ │   ├── images
+ │   ├── javascripts
+ │   └── stylesheets
+ └── test
+ └── controllers
+</code></pre>
+<p>The following compile dependencies will automatically be added to your build:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">ivy&quot;com.typesafe.play::play:${playVersion()}&quot;,
+ivy&quot;com.typesafe.play::play-guice:${playVersion()}&quot;,
+ivy&quot;com.typesafe.play::play-server:${playVersion()}&quot;,
+ivy&quot;com.typesafe.play::play-logback:${playVersion()}&quot;
+</code></pre>
+<p>Scala test will be setup as the default test framework and the following test dependencies will be added (the actual version depends on the version of Play you are pulling <code>2.6.x</code> or <code>2.7.x</code>):</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">ivy&quot;org.scalatestplus.play::scalatestplus-play::4.0.1&quot;
+</code></pre>
+<p>In order to have a working <code>start</code> command the following runtime dependency is also added:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">ivy&quot;com.typesafe.play::play-akka-http-server:${playVersion()}&quot;
+</code></pre><h3 id="using-playapimodule" class="Styles-hoverBox">Using <code>PlayApiModule</code><a href="#using-playapimodule" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The <code>PlayApiModule</code> trait behaves the same as the <code>PlayModule</code> trait but it won't process .scala .html files and you don't need to define the `twirlVersion:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+
+object core extends PlayApiModule {
+ //config
+ override def scalaVersion= T{&quot;2.12.8&quot;}
+ override def playVersion= T{&quot;2.7.0&quot;}
+
+ object test extends PlayTests
+}
+</code></pre><h3 id="play-configuration-options" class="Styles-hoverBox">Play configuration options<a href="#play-configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The Play modules themselves don't have specific configuration options at this point but the <a href="#router-configuration-options">router module configuration options</a> and the <a href="#twirl-configuration-options">Twirl module configuration options</a> are applicable.</p><h3 id="additional-play-libraries" class="Styles-hoverBox">Additional play libraries<a href="#additional-play-libraries" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The following helpers are available to provide additional Play Framework dependencies:</p>
+<ul>
+ <li><code>core()</code> - added by default ,</li>
+ <li><code>guice()</code> - added by default,</li>
+ <li><code>server()</code> - added by default,</li>
+ <li><code>logback()</code> - added by default,</li>
+ <li><code>evolutions()</code> - optional,</li>
+ <li><code>jdbc()</code> - optional,</li>
+ <li><code>filters()</code> - optional,</li>
+ <li><code>ws()</code> - optional,</li>
+ <li><code>caffeine()</code> - optional.</li>
+</ul>
+<p>If you want to add an optional library using the helper you can do so by overriding <code>ivyDeps</code> like in the following example build:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+
+object core extends PlayApiModule {
+ //config
+ override def scalaVersion= T{&quot;2.12.8&quot;}
+ override def playVersion= T{&quot;2.7.0&quot;}
+
+ object test extends PlayTests
+
+ override def ivyDeps = T{ super.ivyDeps() ++ Agg(ws(), filters()) }
+}
+</code></pre><h3 id="commands-equivalence" class="Styles-hoverBox">Commands equivalence<a href="#commands-equivalence" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Mill commands are targets on a named build. For example if your build is called <code>core</code>:</p>
+<ul>
+ <li>compile: <code>core.compile</code></li>
+ <li>run: <em>NOT Implemented yet</em>. It can be approximated with <code>mill -w core.runBackground</code> but this starts a server in <em>PROD</em> mode which:</li>
+ <li>doesn't do any kind of classloading magic (meaning potentially slower restarts)</li>
+ <li>returns less detailed error messages (no source code extract and line numbers)</li>
+ <li>can sometimes fail because of a leftover RUNNING_PID file</li>
+ <li>start: <code>core.start</code> or <code>core.run</code> both start the server in <em>PROD</em> mode.</li>
+ <li>test: <code>core.test</code></li>
+ <li>dist: <em>NOT Implemented yet</em>. However you can use the equivalent <code>core.assembly</code> command to get a runnable fat jar of the project. The packaging is slightly different but should be find for a production deployment.</li>
+</ul><h3 id="using-singlemodule" class="Styles-hoverBox">Using <code>SingleModule</code><a href="#using-singlemodule" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The <code>SingleModule</code> trait allows you to have the build descriptor at the same level as the source code on the filesystem. You can move from there to a multi-module build either by refactoring your directory layout into multiple subdirectories or by using mill's nested modules feature.</p>
+<p>Looking back at the sample build definition in <a href="#using-playmodule">Using PlayModule</a>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+
+object core extends PlayModule {
+ //config
+ override def scalaVersion= T{&quot;2.12.8&quot;}
+ override def playVersion= T{&quot;2.7.0&quot;}
+ override def twirlVersion= T{&quot;1.4.0&quot;}
+
+ object test extends PlayTests
+}
+</code></pre>
+<p>The directory layout was:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
+├── build.sc
+└── core
+ ├── app
+ │   ├── controllers
+ │   └── views
+ ├── conf
+ │   └── application.conf
+ │   └── routes
+ │   └── ...
+ ├── logs
+ ├── public
+ │   ├── images
+ │   ├── javascripts
+ │   └── stylesheets
+ └── test
+ └── controllers
+</code></pre>
+<p>by mixing in the <code>SingleModule</code> trait in your build:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+
+object core extends PlayModule with SingleModule {
+ //config
+ override def scalaVersion= T{&quot;2.12.8&quot;}
+ override def playVersion= T{&quot;2.7.0&quot;}
+ override def twirlVersion= T{&quot;1.4.0&quot;}
+
+ object test extends PlayTests
+}
+</code></pre>
+<p>the layout becomes:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
+└── core
+ ├── build.sc
+ ├── app
+ │   ├── controllers
+ │   └── views
+ ├── conf
+ │   └── application.conf
+ │   └── routes
+ │   └── ...
+ ├── logs
+ ├── public
+ │   ├── images
+ │   ├── javascripts
+ │   └── stylesheets
+ └── test
+ └── controllers
+</code></pre><h4 id="using-the-router-module-directly" class="Styles-hoverBox">Using the router module directly<a href="#using-the-router-module-directly" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h4>
+<p>If you want to use the router module in a project which doesn't use the default Play layout, you can mix-in the <code>mill.playlib.routesModule</code> trait directly when defining your module. Your app must define <code>playVersion</code> and <code>scalaVersion</code>.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+
+object app extends ScalaModule with RouterModule {
+ def playVersion= T{&quot;2.7.0&quot;}
+ def scalaVersion= T{&quot;2.12.8&quot;}
+}
+</code></pre><h5 id="router-configuration-options" class="Styles-hoverBox">Router Configuration options<a href="#router-configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h5>
+<ul>
+ <li><code>def playVersion: T[String]</code> (mandatory) - The version of Play to use to compile the routes file.</li>
+ <li><code>def scalaVersion: T[String]</code> - The scalaVersion in use in your project.</li>
+ <li><code>def routes: Sources</code> - The directory which contains your route files. (Defaults to : <code>routes/</code>)</li>
+ <li><code>def routesAdditionalImport: Seq[String]</code> - Additional imports to use in the generated routers. (Defaults to <code>Seq(&quot;controllers.Assets.Asset&quot;, &quot;play.libs.F&quot;)</code></li>
+ <li><code>def generateForwardsRouter: Boolean = true</code> - Enables the forward router generation.</li>
+ <li><code>def generateReverseRouter: Boolean = true</code> - Enables the reverse router generation.</li>
+ <li><code>def namespaceReverseRouter: Boolean = false</code> - Enables the namespacing of reverse routers.</li>
+ <li><code>def generatorType: RouteCompilerType = RouteCompilerType.InjectedGenerator</code> - The routes compiler type, one of RouteCompilerType.InjectedGenerator or RouteCompilerType.StaticGenerator</li>
+</ul><h5 id="details" class="Styles-hoverBox">Details<a href="#details" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h5>
+<p>The following filesystem layout is expected by default:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
+├── app
+│   └── routes
+│   └── routes
+└── build.sc
+</code></pre>
+<p><code>RouterModule</code> adds the <code>compileRouter</code> task to the module:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">mill app.compileRouter
+</code></pre>
+<p>(it will be automatically run whenever you compile your module)</p>
+<p>This task will compile <code>routes</code> templates into the <code>out/app/compileRouter/dest</code> directory. This directory must be added to the generated sources of the module to be compiled and made accessible from the rest of the code. This is done by default in the trait, but if you need to have a custom override for <code>generatedSources</code> you can get the list of files from <code>routerClasses</code></p>
+<p>To add additional imports to all of the routes:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill.scalalib._
+
+import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._
+
+object app extends ScalaModule with RouterModule {
+ def playVersion = &quot;2.7.0&quot;
+ override def routesAdditionalImport = Seq(&quot;my.additional.stuff._&quot;, &quot;my.other.stuff._&quot;)
+}
+</code></pre><h2 id="scalapb" class="Styles-hoverBox">ScalaPB<a href="#scalapb" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>This module allows <a href="https://scalapb.github.io">ScalaPB</a> to be used in Mill builds. ScalaPB is a <a href="https://developers.google.com/protocol-buffers/">Protocol Buffers</a> compiler plugin that generates Scala case classes, encoders and decoders for protobuf messages.</p>
+<p>To declare a module that uses ScalaPB you can extend the <code>mill.contrib.scalapblib.ScalaPBModule</code> trait when defining your module.</p>
+<p>This creates a Scala module which compiles <code>.proto</code> files in the <code>protobuf</code> folder of the module with ScalaPB and adds the resulting <code>.scala</code> sources to your module's <code>generatedSources</code>.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+
+import $ivy.`com.lihaoyi::mill-contrib-scalapblib:$MILL_VERSION`
+import contrib.scalapblib._
+
+object example extends ScalaPBModule {
+ def scalaVersion = &quot;2.12.6&quot;
+ def scalaPBVersion = &quot;0.7.4&quot;
+}
+</code></pre>
+<p>This defines a project with the following layout:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">build.sc
+example/
+ src/
+ protobuf/
+ resources/
+</code></pre><h3 id="configuration-options" class="Styles-hoverBox">Configuration options<a href="#configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li>
+ <p>scalaPBVersion (mandatory) - The ScalaPB version <code>String</code> e.g. <code>&quot;0.7.4&quot;</code></p></li>
+ <li>
+ <p>scalaPBFlatPackage - A <code>Boolean</code> option which determines whether the <code>.proto</code> file name should be appended as the final segment of the package name in the generated sources.</p></li>
+ <li>
+ <p>scalaPBJavaConversions - A <code>Boolean</code> option which determines whether methods for converting between the generated Scala classes and the Protocol Buffers Java API classes should be generated.</p></li>
+ <li>
+ <p>scalaPBGrpc - A <code>Boolean</code> option which determines whether <a href="https://grpc.io">grpc</a> stubs should be generated.</p></li>
+ <li>
+ <p>scalaPBSingleLineToProtoString - A <code>Boolean</code> option which determines whether the generated <code>.toString</code> methods should use a single line format.</p></li>
+</ul>
+<p>If you'd like to configure the options that are passed to the ScalaPB compiler directly, you can override the <code>scalaPBOptions</code> task, for example:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+
+import $ivy.`com.lihaoyi::mill-contrib-scalapblib:$MILL_VERSION`
+import contrib.scalapblib._
+
+object example extends ScalaPBModule {
+ def scalaVersion = &quot;2.12.6&quot;
+ def scalaPBVersion = &quot;0.7.4&quot;
+ override def scalaPBOptions = &quot;flat_package,java_conversions&quot;
+}
+</code></pre><h2 id="scoverage" class="Styles-hoverBox">Scoverage<a href="#scoverage" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>This module allows you to generate code coverage reports for Scala projects with <a href="https://github.com/scoverage">Scoverage</a> via the <a href="https://github.com/scoverage/scalac-scoverage-plugin">scalac-scoverage-plugin</a>.</p>
+<p>To declare a module for which you want to generate coverage reports you can extends the <code>mill.contrib.scoverage.ScoverageModule</code> trait when defining your module. Additionally, you must define a submodule that extends the <code>ScoverageTests</code> trait that belongs to your instance of <code>ScoverageModule</code>.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import $ivy.`com.lihaoyi::mill-contrib-scoverage:$MILL_VERSION`
+import mill.contrib.scoverage.ScoverageModule
+
+object foo extends ScoverageModule {
+ def scalaVersion = &quot;2.12.9&quot;
+ def scoverageVersion = &quot;1.4.0&quot;
+
+ object test extends ScoverageTests {
+ def ivyDeps = Agg(ivy&quot;org.scalatest::scalatest:3.0.8&quot;)
+ def testFrameworks = Seq(&quot;org.scalatest.tools.Framework&quot;)
+ }
+}
+</code></pre>
+<p>In addition to the normal tasks available to your Scala module, Scoverage modules introduce a few new tasks and changes the behavior of an existing one.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">mill foo.scoverage.compile # compiles your module with test instrumentation
+ # (you don&#39;t have to run this manually, running the test task will force its invocation)
+
+mill foo.test # tests your project and collects metrics on code coverage
+mill foo.scoverage.htmlReport # uses the metrics collected by a previous test run to generate a coverage report in html format
+mill foo.scoverage.xmlReport # uses the metrics collected by a previous test run to generate a coverage report in xml format
+</code></pre>
+<p>The measurement data is available at <code>out/foo/scoverage/data/</code>, the html report is saved in <code>out/foo/scoverage/htmlReport/</code>, and the xml report is saved in <code>out/foo/scoverage/xmlReport/</code>.</p><h2 id="testng" class="Styles-hoverBox">TestNG<a href="#testng" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Provides support for <a href="https://testng.org/doc/index.html">TestNG</a>.</p>
+<p>To use TestNG as test framework, you need to add it to the <code>TestModule.testFrameworks</code> property.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill.scalalib._
+
+object project extends ScalaModule {
+ object test extends Tests{
+ def testFrameworks = Seq(&quot;mill.testng.TestNGFramework&quot;)
+ }
+}
+</code></pre><h2 id="tut" class="Styles-hoverBox">Tut<a href="#tut" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>This module allows <a href="https://tpolecat.github.io/tut">Tut</a> 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.</p>
+<p>To declare a module that uses Tut you can extend the <code>mill.contrib.tut.TutModule</code> trait when defining your module.</p>
+<p>This creates a Scala module which compiles markdown, HTML and <code>.txt</code> files in the <code>tut</code> folder of the module with Tut.</p>
+<p>By default the resulting documents are simply placed in the Mill build output folder but they can be placed elsewhere by overriding the <code>tutTargetDirectory</code> task.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+
+import $ivy.`com.lihaoyi::mill-contrib-tut:$MILL_VERSION`
+import contrib.tut._
+
+object example extends TutModule {
+ def scalaVersion = &quot;2.12.6&quot;
+ def tutVersion = &quot;0.6.7&quot;
+}
+</code></pre>
+<p>This defines a project with the following layout:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">build.sc
+example/
+ src/
+ tut/
+ resources/
+</code></pre>
+<p>In order to compile documentation we can execute the <code>tut</code> task in the module:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">sh&gt; mill example.tut
+</code></pre><h3 id="configuration-options" class="Styles-hoverBox">Configuration options<a href="#configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li>
+ <p>tutSourceDirectory - This task determines where documentation files must be placed in order to be compiled with Tut. By default this is the <code>tut</code> folder at the root of the module.</p></li>
+ <li>
+ <p>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 <code>tutTargetDirectory</code> task but this can be reconfigured so that documentation goes to the root of the module (e.g. <code>millSourcePath</code>) or to a dedicated folder (e.g. <code>millSourcePath / &#39;docs</code>)</p></li>
+ <li>
+ <p>tutClasspath - A task which determines what classpath is used when compiling documentation. By default this is configured to use the same inputs as the <code>runClasspath</code>, except for using <code>tutIvyDeps</code> rather than the module's <code>ivyDeps</code>.</p></li>
+ <li>
+ <p>tutScalacPluginIvyDeps - A task which determines the scalac plugins which will be used when compiling code examples with Tut. The default is to use the <code>scalacPluginIvyDeps</code> for the module.</p></li>
+ <li>
+ <p>tutNameFilter - A <code>scala.util.matching.Regex</code> task which will be used to determine which files should be compiled with tut. The default pattern is as follows: <code>.*\.(md|markdown|txt|htm|html)</code>.</p></li>
+ <li>
+ <p>tutScalacOptions - The scalac options which will be used when compiling code examples with Tut. The default is to use the <code>scalacOptions</code> for the module but filtering out options which are problematic in the REPL, e.g. <code>-Xfatal-warnings</code>, <code>-Ywarn-unused-imports</code>.</p></li>
+ <li>
+ <p>tutVersion - The version of Tut to use.</p></li>
+ <li>
+ <p>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.</p></li>
+ <li>
+ <p>tutPluginJars - A task which performs the dependency resolution for the scalac plugins to be used with Tut.</p></li>
+</ul><h2 id="twirl" class="Styles-hoverBox">Twirl<a href="#twirl" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Twirl templates support.</p>
+<p>To declare a module that needs to compile twirl templates you must extend the <code>mill.twirllib.TwirlModule</code> trait when defining your module. Also note that twirl templates get compiled into scala code, so you also need to extend <code>ScalaModule</code>.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill.scalalib._
+
+import $ivy.`com.lihaoyi::mill-contrib-twirllib:$MILL_VERSION`, mill.twirllib._
+
+object app extends ScalaModule with TwirlModule {
+// ...
+}
+</code></pre><h3 id="twirl-configuration-options" class="Styles-hoverBox">Twirl configuration options<a href="#twirl-configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><code>def twirlVersion: T[String]</code> (mandatory) - the version of the twirl compiler to use, like "1.3.15"</li>
+ <li><code>def twirlAdditionalImports: Seq[String] = Nil</code> - the additional imports that will be added by twirl compiler to the top of all templates</li>
+ <li><code>def twirlConstructorAnnotations: Seq[String] = Nil</code> - annotations added to the generated classes' constructors (note it only applies to templates with <code>@this(...)</code> constructors)</li>
+ <li><code>def twirlCodec = Codec(Properties.sourceEncoding)</code> - the codec used to generate the files (the default is the same sbt plugin uses)</li>
+ <li><code>def twirlInclusiveDot: Boolean = false</code></li>
+</ul><h3 id="details" class="Styles-hoverBox">Details<a href="#details" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The following filesystem layout is expected:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">build.sc
+app/
+ views/
+ view1.scala.html
+ view2.scala.html
+</code></pre>
+<p><code>TwirlModule</code> adds the <code>compileTwirl</code> task to the module:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">mill app.compileTwirl
+</code></pre>
+<p>(it will be automatically run whenever you compile your module)</p>
+<p>This task will compile <code>*.scala.html</code> templates (and others, like <code>*.scala.txt</code>) into the <code>out/app/compileTwirl/dest</code> directory. This directory must be added to the generated sources of the module to be compiled and made accessible from the rest of the code:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill.scalalib._
+
+import $ivy.`com.lihaoyi::mill-contrib-twirllib:$MILL_VERSION`, mill.twirllib._
+
+object app extends ScalaModule with TwirlModule {
+ def twirlVersion = &quot;1.3.15&quot;
+ def generatedSources = T{ Seq(compileTwirl().classes) }
+}
+</code></pre>
+<p>To add additional imports to all of the twirl templates:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill.scalalib._
+
+import $ivy.`com.lihaoyi::mill-contrib-twirllib:$MILL_VERSION`, mill.twirllib._
+
+object app extends ScalaModule with TwirlModule {
+ def twirlVersion = &quot;1.3.15&quot;
+ override def twirlAdditionalImports = Seq(&quot;my.additional.stuff._&quot;, &quot;my.other.stuff._&quot;)
+ def generatedSources = T{ Seq(compileTwirl().classes) }
+}
+</code></pre>
+<p>as the result all templates will get this line at the top:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">@import &quot;my.additional.stuff._&quot;
+@import &quot;my.other.stuff._&quot;
+</code></pre>
+<p>Besides that, twirl compiler has default imports, at the moment these:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">Seq(
+ &quot;_root_.play.twirl.api.TwirlFeatureImports._&quot;,
+ &quot;_root_.play.twirl.api.TwirlHelperImports._&quot;,
+ &quot;_root_.play.twirl.api.Html&quot;,
+ &quot;_root_.play.twirl.api.JavaScript&quot;,
+ &quot;_root_.play.twirl.api.Txt&quot;,
+ &quot;_root_.play.twirl.api.Xml&quot;
+)
+</code></pre>
+<p>These imports will always be added to every template. You don't need to list them if you override <code>twirlAdditionalImports</code>.</p><h3 id="example" class="Styles-hoverBox">Example<a href="#example" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>There's an <a href="https://github.com/lihaoyi/cask/tree/master/example/twirl">example project</a></p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="mill-internals.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Mill Internals</a><a href="thirdparty-modules.html">Thirdparty Modules <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/cross-builds.html b/page/cross-builds.html
new file mode 100644
index 00000000..52e2cac3
--- /dev/null
+++ b/page/cross-builds.html
@@ -0,0 +1,220 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Cross Builds</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#defining-cross-modules">Defining Cross Modules</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-cross-modules-from-outside">Using Cross Modules from Outside</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-cross-modules-from-other-cross-modules">Using Cross Modules from other Cross Modules</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#cross-resolvers">Cross Resolvers</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Cross Builds</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="modules.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Modules</a><a href="extending-mill.html">Extending Mill <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><p>Mill handles cross-building of all sorts via the <code>Cross[T]</code> module.</p><h2 id="defining-cross-modules" class="Styles-hoverBox">Defining Cross Modules<a href="#defining-cross-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>You can use this as follows:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Cross[FooModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class FooModule(crossVersion: String) extends Module {
+ def suffix = T { crossVersion }
+ def bigSuffix = T { suffix().toUpperCase() }
+}
+</code></pre>
+<p>This defines three copies of <code>FooModule</code>: <code>&quot;210&quot;</code>, <code>&quot;211&quot;</code> and <code>&quot;212&quot;</code>, each of which has their own <code>suffix</code> target. You can then run them via</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill show foo[2.10].suffix
+mill show foo[2.10].bigSuffix
+mill show foo[2.11].suffix
+mill show foo[2.11].bigSuffix
+mill show foo[2.12].suffix
+mill show foo[2.12].bigSuffix
+</code></pre>
+<p>The modules each also have a <code>millSourcePath</code> of</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">foo/2.10
+foo/2.11
+foo/2.12
+</code></pre>
+<p>And the <code>suffix</code> targets will have the corresponding output paths for their metadata and files:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">foo/2.10/suffix
+foo/2.10/bigSuffix
+foo/2.11/suffix
+foo/2.11/bigSuffix
+foo/2.12/suffix
+foo/2.12/bigSuffix
+</code></pre>
+<p>You can also have a cross-build with multiple inputs:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">val crossMatrix = for {
+ crossVersion &lt;- Seq(&quot;210&quot;, &quot;211&quot;, &quot;212&quot;)
+ platform &lt;- Seq(&quot;jvm&quot;, &quot;js&quot;, &quot;native&quot;)
+ if !(platform == &quot;native&quot; &amp;&amp; crossVersion != &quot;212&quot;)
+} yield (crossVersion, platform)
+
+object foo extends mill.Cross[FooModule](crossMatrix:_*)
+class FooModule(crossVersion: String, platform: String) extends Module {
+ def suffix = T { crossVersion + &quot;_&quot; + platform }
+}
+</code></pre>
+<p>Here, we define our cross-values programmatically using a <code>for</code>-loop that spits out tuples instead of individual values. Our <code>FooModule</code> template class then takes two parameters instead of one. This creates the following modules each with their own <code>suffix</code> target:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill show foo[210,jvm].suffix
+mill show foo[211,jvm].suffix
+mill show foo[212,jvm].suffix
+mill show foo[210,js].suffix
+mill show foo[211,js].suffix
+mill show foo[212,js].suffix
+mill show foo[212,native].suffix
+</code></pre><h2 id="using-cross-modules-from-outside" class="Styles-hoverBox">Using Cross Modules from Outside<a href="#using-cross-modules-from-outside" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>You can refer to targets defined in cross-modules as follows:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Cross[FooModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class FooModule(crossVersion: String) extends Module {
+ def suffix = T { crossVersion }
+}
+
+def bar = T { &quot;hello &quot; + foo(&quot;2.10&quot;).suffix }
+</code></pre>
+<p>Here, <code>foo(&quot;2.10&quot;)</code> references the <code>&quot;2.10&quot;</code> instance of <code>FooModule</code>. You can refer to whatever versions of the cross-module you want, even using multiple versions of the cross-module in the same target:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Cross[FooModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class FooModule(crossVersion: String) extends Module {
+ def suffix = T { crossVersion }
+}
+
+def bar = T { &quot;hello &quot; + foo(&quot;2.10&quot;).suffix + &quot; world &quot; + foo(&quot;2.12&quot;).suffix }
+</code></pre><h2 id="using-cross-modules-from-other-cross-modules" class="Styles-hoverBox">Using Cross Modules from other Cross Modules<a href="#using-cross-modules-from-other-cross-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Targets in cross-modules can depend on one another the same way that external targets:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Cross[FooModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class FooModule(crossVersion: String) extends Module {
+ def suffix = T { crossVersion }
+}
+
+object bar extends mill.Cross[BarModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class BarModule(crossVersion: String) extends Module {
+ def bigSuffix = T { foo(crossVersion).suffix().toUpperCase() }
+}
+</code></pre>
+<p>Here, you can run:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill show foo[2.10].suffix
+mill show foo[2.11].suffix
+mill show foo[2.12].suffix
+mill show bar[2.10].bigSuffix
+mill show bar[2.11].bigSuffix
+mill show bar[2.12].bigSuffix
+</code></pre><h2 id="cross-resolvers" class="Styles-hoverBox">Cross Resolvers<a href="#cross-resolvers" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>You can define an implicit <code>mill.define.Cross.Resolver</code> within your cross-modules, which would let you use a shorthand <code>foo()</code> syntax when referring to other cross-modules with an identical set of cross values:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">trait MyModule extends Module {
+ def crossVersion: String
+ implicit object resolver extends mill.define.Cross.Resolver[MyModule] {
+ def resolve[V &lt;: MyModule](c: Cross[V]): V = c.itemMap(List(crossVersion))
+ }
+}
+
+object foo extends mill.Cross[FooModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class FooModule(val crossVersion: String) extends MyModule {
+ def suffix = T { crossVersion }
+}
+
+object bar extends mill.Cross[BarModule](&quot;2.10&quot;, &quot;2.11&quot;, &quot;2.12&quot;)
+class BarModule(val crossVersion: String) extends MyModule {
+ def longSuffix = T { &quot;_&quot; + foo().suffix() }
+}
+</code></pre>
+<p>While the example <code>resolver</code> simply looks up the target <code>Cross</code> value for the cross-module instance with the same <code>crossVersion</code>, you can make the resolver arbitrarily complex. E.g. the <code>resolver</code> for <code>mill.scalalib.CrossSbtModule</code> looks for a cross-module instance whose <code>scalaVersion</code> is binary compatible (e.g. 2.10.5 is compatible with 2.10.3) with the current cross-module.</p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="modules.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Modules</a><a href="extending-mill.html">Extending Mill <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/extending-mill.html b/page/extending-mill.html
new file mode 100644
index 00000000..f6c7d0e7
--- /dev/null
+++ b/page/extending-mill.html
@@ -0,0 +1,210 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Extending Mill</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#custom-targets--commands">Custom Targets &amp; Commands</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#compile-some-javascript-with-webpack-and-put-it-in-your-runtime-classpath">Compile some Javascript with Webpack and put it in your runtime classpath:</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#deploy-your-compiled-assembly-to-aws">Deploy your compiled assembly to AWS</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#custom-workers">Custom Workers</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#custom-modules">Custom Modules</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#import-file">import $file</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#import-ivy">import $ivy</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#evaluator-commands-experimental">Evaluator Commands (experimental)</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Extending Mill</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="cross-builds.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Cross Builds</a><a href="mill-internals.html">Mill Internals <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><p>There are many different ways of extending Mill, depending on how much customization and flexibility you need. This page will go through your options from the easiest/least-flexible to the hardest/most-flexible.</p><h2 id="custom-targets--commands" class="Styles-hoverBox">Custom Targets &amp; Commands<a href="#custom-targets--commands" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>The simplest way of adding custom functionality to Mill is to define a custom Target or Command:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def foo = T { ... }
+def bar(x: Int, s: String) = T.command { ... }
+</code></pre>
+<p>These can depend on other Targets, contain arbitrary code, and be placed top-level or within any module. If you have something you just want to <em>do</em> that isn't covered by the built-in <code>ScalaModule</code>s/<code>ScalaJSModule</code>s, simply write a custom Target (for cached computations) or Command (for un-cached actions) and you're done.</p>
+<p>For subprocess/filesystem operations, you can use the <a href="http://ammonite.io/#Ammonite-Ops">Ammonite-Ops</a> library that comes bundled with Mill, or even plain <code>java.nio</code>/<code>java.lang.Process</code>. Each target gets its own <a href="http://www.lihaoyi.com/mill/page/tasks#millutilctxdestctx">T.ctx().dest</a> folder that you can use to place files without worrying about colliding with other targets.</p>
+<p>This covers use cases like:</p><h3 id="compile-some-javascript-with-webpack-and-put-it-in-your-runtime-classpath" class="Styles-hoverBox">Compile some Javascript with Webpack and put it in your runtime classpath:<a href="#compile-some-javascript-with-webpack-and-put-it-in-your-runtime-classpath" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def doWebpackStuff(sources: Seq[PathRef]): PathRef = ???
+
+def javascriptSources = T.sources { millSourcePath / &quot;js&quot; }
+def compiledJavascript = T { doWebpackStuff(javascriptSources()) }
+object foo extends ScalaModule {
+ def runClasspath = T { super.runClasspath() ++ compiledJavascript() }
+}
+</code></pre><h3 id="deploy-your-compiled-assembly-to-aws" class="Styles-hoverBox">Deploy your compiled assembly to AWS<a href="#deploy-your-compiled-assembly-to-aws" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends ScalaModule {
+
+}
+
+def deploy(assembly: PathRef, credentials: String) = ???
+
+def deployFoo(credentials: String) = T.command { deployFoo(foo.assembly()) }
+</code></pre><h2 id="custom-workers" class="Styles-hoverBox">Custom Workers<a href="#custom-workers" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p><a href="#custom-targets--commands">Custom Targets &amp; Commands</a> are re-computed from scratch each time; sometimes you want to keep values around in-memory when using <code>--watch</code> or the Build REPL. E.g. you may want to keep a webpack process running so webpack's own internal caches are hot and compilation is fast:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def webpackWorker = T.worker {
+ // Spawn a process using java.lang.Process and return it
+}
+
+def javascriptSources = T.sources { millSourcePath / &quot;js&quot; }
+
+def doWebpackStuff(webpackProcess: Process, sources: Seq[PathRef]): PathRef = ???
+
+def compiledJavascript = T { doWebpackStuff(webpackWorker(), javascriptSources()) }
+</code></pre>
+<p>Mill itself uses <code>T.worker</code>s for its built-in Scala support: we keep the Scala compiler in memory between compilations, rather than discarding it each time, in order to improve performance.</p><h2 id="custom-modules" class="Styles-hoverBox">Custom Modules<a href="#custom-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">trait FooModule extends mill.Module {
+ def bar = T { &quot;hello&quot; }
+ def baz = T { &quot;world&quot; }
+}
+</code></pre>
+<p>Custom modules are useful if you have a common set of tasks that you want to re-used across different parts of your build. You simply define a <code>trait</code> inheriting from <code>mill.Module</code>, and then use that <code>trait</code> as many times as you want in various <code>object</code>s:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo1 extends FooModule
+object foo2 extends FooModule {
+ def qux = T { &quot;I am Cow&quot; }
+}
+</code></pre>
+<p>You can also define a <code>trait</code> extending the built-in <code>ScalaModule</code> if you have common configuration you want to apply to all your <code>ScalaModule</code>s:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">trait FooModule extends ScalaModule {
+ def scalaVersion = &quot;2.11.11&quot;
+ object test extends Tests {
+ def ivyDeps = Agg(ivy&quot;org.scalatest::scalatest:3.0.4&quot;)
+ def testFrameworks = Seq(&quot;org.scalatest.tools.Framework&quot;)
+ }
+}
+</code></pre><h2 id="import-file" class="Styles-hoverBox">import $file<a href="#import-file" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>If you want to define some functionality that can be used both inside and outside the build, you can create a new <code>foo.sc</code> file next to your <code>build.sc</code>, <code>import $file.foo</code>, and use it in your <code>build.sc</code> file:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// foo.sc
+def fooValue() = 31337
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import $file.foo
+def printFoo() = T.command { println(foo.fooValue()) }
+</code></pre>
+<p>Mill's <code>import $file</code> syntax supports the full functionality of <a href="http://ammonite.io/#ScalaScripts">Ammonite Scripts</a></p><h2 id="import-ivy" class="Styles-hoverBox">import $ivy<a href="#import-ivy" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>If you want to pull in artifacts from the public repositories (e.g. Maven Central) for use in your build, you can simply use <code>import $ivy</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import $ivy.`com.lihaoyi::scalatags:0.6.2`
+
+def generatedHtml = T {
+ import scalatags.Text.all._
+ html(
+ head(),
+ body(
+ h1(&quot;Hello&quot;),
+ p(&quot;World&quot;)
+ )
+ ).render
+}
+</code></pre>
+<p>This creates the <code>generatedHtml</code> target which can then be used however you would like: written to a file, further processed, etc.</p>
+<p>If you want to publish re-usable libraries that <em>other</em> people can use in their builds, simply publish your code as a library to maven central.</p>
+<p>For more information, see Ammonite's <a href="http://ammonite.io/#import$ivy">Ivy Dependencies documentation</a>.</p><h2 id="evaluator-commands-experimental" class="Styles-hoverBox">Evaluator Commands (experimental)<a href="#evaluator-commands-experimental" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p><em>Evaluator Command are experimental and suspected to change. See <a href="https://github.com/lihaoyi/mill/issues/502">issue #502</a> for details.</em></p>
+<p>You can define a command that takes in the current <code>Evaluator</code> as an argument, which you can use to inspect the entire build, or run arbitrary tasks. For example, here is the <code>mill.scalalib.GenIdea/idea</code> command which uses this to traverse the module-tree and generate an Intellij project config for your build.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def idea(ev: Evaluator) = T.command {
+ mill.scalalib.GenIdea(
+ implicitly,
+ ev.rootModule,
+ ev.discover
+ )
+}
+</code></pre>
+<p>Many built-in tools are implemented as custom evaluator commands: <a href="http://www.lihaoyi.com/mill/#all">all</a>, <a href="http://www.lihaoyi.com/mill/#inspect">inspect</a>, <a href="http://www.lihaoyi.com/mill/#resolve">resolve</a>, <a href="http://www.lihaoyi.com/mill/#show">show</a>. If you want a way to run Mill commands and programmatically manipulate the tasks and outputs, you do so with your own evaluator command.</p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="cross-builds.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Cross Builds</a><a href="mill-internals.html">Mill Internals <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/mill-internals.html b/page/mill-internals.html
new file mode 100644
index 00000000..acaccbf9
--- /dev/null
+++ b/page/mill-internals.html
@@ -0,0 +1,264 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Mill Internals</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#mill-design-principles">Mill Design Principles</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#dependency-graph-first">Dependency graph first</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#builds-are-hierarchical">Builds are hierarchical</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#caching-by-default">Caching by default</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#short-lived-build-processes">Short-lived build processes</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#static-dependency-graph-and-applicative-tasks">Static dependency graph and Applicative tasks</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#how-mill-aims-for-simple">How Mill aims for Simple</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#the-object-hierarchy">The Object Hierarchy</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#the-call-graph">The Call Graph</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#instantiating-traits--classes">Instantiating Traits &amp; Classes</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#prior-work">Prior Work</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#sbt">SBT</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#bazel">Bazel</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#scalarx">Scala.Rx</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#cbt">CBT</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Mill Internals</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="extending-mill.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Extending Mill</a><a href="contrib-modules.html">Contrib Modules <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><h2 id="mill-design-principles" class="Styles-hoverBox">Mill Design Principles<a href="#mill-design-principles" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>A lot of Mill's design principles are intended to fix SBT's flaws, as described in the blog post <a href="http://www.lihaoyi.com/post/SowhatswrongwithSBT.html">What's wrong with SBT</a>, building on the best ideas from tools like <a href="https://github.com/cvogt/cbt">CBT</a> and <a href="https://bazel.build/">Bazel</a>, and the ideas from my blog post <a href="http://www.lihaoyi.com/post/BuildToolsasPureFunctionalPrograms.html">Build Tools as Pure Functional Programs</a>. Before working on Mill, read through that post to understand where it is coming from!</p><h3 id="dependency-graph-first" class="Styles-hoverBox">Dependency graph first<a href="#dependency-graph-first" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Mill's most important abstraction is the dependency graph of <code>Task</code>s. Constructed using the <code>T {...}</code> <code>T.task {...}</code> <code>T.command {...}</code> syntax, these track the dependencies between steps of a build, so those steps can be executed in the correct order, queried, or parallelized.</p>
+<p>While Mill provides helpers like <code>ScalaModule</code> and other things you can use to quickly instantiate a bunch of related tasks (resolve dependencies, find sources, compile, package into jar, ...) these are secondary. When Mill executes, the dependency graph is what matters: any other mode of organization (hierarchies, modules, inheritance, etc.) is only important to create this dependency graph of <code>Task</code>s.</p><h3 id="builds-are-hierarchical" class="Styles-hoverBox">Builds are hierarchical<a href="#builds-are-hierarchical" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The syntax for running targets from the command line <code>mill Foo.bar.baz</code> is the same as referencing a target in Scala code, <code>Foo.bar.baz</code></p>
+<p>Everything that you can run from the command line lives in an object hierarchy in your <code>build.sc</code> file. Different parts of the hierarchy can have different <code>Target</code>s available: just add a new <code>def foo = T {...}</code> somewhere and you'll be able to run it.</p>
+<p>Cross builds, using the <code>Cross</code> data structure, are just another kind of node in the object hierarchy. The only difference is syntax: from the command line you'd run something via <code>mill core.cross[a].printIt</code> while from code you use <code>core.cross(&quot;a&quot;).printIt</code> due to different restrictions in Scala/Bash syntax.</p><h3 id="caching-by-default" class="Styles-hoverBox">Caching by default<a href="#caching-by-default" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Every <code>Target</code> in a build, defined by <code>def foo = T {...}</code>, is cached by default. Currently this is done using a <code>foo/meta.json</code> file in the <code>out/</code> folder. The <code>Target</code> is also provided a <code>foo/</code> path on the filesystem dedicated to it, for it to store output files etc.</p>
+<p>This happens whether you want it to or not. Every <code>Target</code> is cached, not just the "slow" ones like <code>compile</code> or <code>assembly</code>.</p>
+<p>Caching is keyed on the <code>.hashCode</code> of the returned value. For <code>Target</code>s returning the contents of a file/folder on disk, they return <code>PathRef</code> instances whose hashcode is based on the hash of the disk contents. Serialization of the returned values is tentatively done using uPickle.</p><h3 id="short-lived-build-processes" class="Styles-hoverBox">Short-lived build processes<a href="#short-lived-build-processes" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The Mill build process is meant to be run over and over, not only as a long-lived daemon/console. That means we must minimize the startup time of the process, and that a new process must be able to re-construct the in-memory data structures where a previous process left off, in order to continue the build.</p>
+<p>Re-construction is done via the hierarchical nature of the build: each <code>Target</code> <code>foo.bar.baz</code> has a fixed position in the build hierarchy, and thus a fixed position on disk <code>out/foo/bar/baz/meta.json</code>. When the old process dies and a new process starts, there will be a new instance of <code>Target</code> with the same implementation code and same position in the build hierarchy: this new <code>Target</code> can then load the <code>out/foo/bar/baz/meta.json</code> file and pick up where the previous process left off.</p>
+<p>Minimizing startup time means aggressive caching, as well as minimizing the total amount of bytecode used: Mill's current 1-2s startup time is dominated by JVM classloading. In future, we may have a long lived console or nailgun/drip-based server/client models to speed up interactive usage, but we should always keep "cold" startup as fast as possible.</p><h3 id="static-dependency-graph-and-applicative-tasks" class="Styles-hoverBox">Static dependency graph and Applicative tasks<a href="#static-dependency-graph-and-applicative-tasks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p><code>Task</code>s are <em>Applicative</em>, not <em>Monadic</em>. There is <code>.map</code>, <code>.zip</code>, but no <code>.flatMap</code> operation. That means that we can know the structure of the entire dependency graph before we start executing <code>Task</code>s. This lets us perform all sorts of useful operations on the graph before running it:</p>
+<ul>
+ <li>
+ <p>Given a Target the user wants to run, pre-compute and display what targets will be evaluated ("dry run"), without running them</p></li>
+ <li>
+ <p>Automatically parallelize different parts of the dependency graph that do not depend on each other, perhaps even distributing it to different worker machines like Bazel/Pants can</p></li>
+ <li>
+ <p>Visualize the dependency graph easily, e.g. by dumping to a DOT file</p></li>
+ <li>
+ <p>Query the graph, e.g. "why does this thing depend on that other thing?"</p></li>
+ <li>
+ <p>Avoid running tasks "halfway": if a Target's upstream Targets fail, we can skip the Target completely rather than running halfway and then bailing out with an exception</p></li>
+</ul>
+<p>In order to avoid making people using <code>.map</code> and <code>.zip</code> all over the place when defining their <code>Task</code>s, we use the <code>T {...}</code>/<code>T.task {...}</code>/<code>T.command {...}</code> macros which allow you to use <code>Task#apply()</code> within the block to "extract" a value.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def test() = T.command {
+ TestRunner.apply(
+ &quot;mill.UTestFramework&quot;,
+ runDepClasspath().map(_.path) :+ compile().path,
+ Seq(compile().path)
+
+}
+</code></pre>
+<p>This is roughly equivalent to the following:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def test() = T.command { T.zipMap(runDepClasspath, compile, compile) {
+ (runDepClasspath1, compile2, compile3) =&gt;
+ TestRunner.apply(
+ &quot;mill.UTestFramework&quot;,
+ runDepClasspath1.map(_.path) :+ compile2.path,
+ Seq(compile3.path)
+ )
+}
+</code></pre>
+<p>This is similar to SBT's <code>:=</code>/<code>.value</code> macros, or <code>scala-async</code>'s <code>async</code>/<code>await</code>. Like those, the <code>T {...}</code> macro should let users program most of their code in a "direct" style and have it "automatically" lifted into a graph of <code>Task</code>s.</p><h2 id="how-mill-aims-for-simple" class="Styles-hoverBox">How Mill aims for Simple<a href="#how-mill-aims-for-simple" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Why should you expect that the Mill build tool can achieve simple, easy &amp; flexible, where other build tools in the past have failed?</p>
+<p>Build tools inherently encompass a huge number of different concepts:</p>
+<ul>
+ <li>What "Tasks" depends on what?</li>
+ <li>How do I define my own tasks?</li>
+ <li>Where do source files come from?</li>
+ <li>What needs to run in what order to do what I want?</li>
+ <li>What can be parallelized and what can't?</li>
+ <li>How do tasks pass data to each other? What data do they pass?</li>
+ <li>What tasks are cached? Where?</li>
+ <li>How are tasks run from the command line?</li>
+ <li>How do you deal with the repetition inherent in a build? (e.g. compile, run &amp; test tasks for every "module")</li>
+ <li>What is a "Module"? How do they relate to "Tasks"?</li>
+ <li>How do you configure a Module to do something different?</li>
+ <li>How are cross-builds (across different configurations) handled?</li>
+</ul>
+<p>These are a lot of questions to answer, and we haven't even started talking about the actually compiling/running any code yet! If each such facet of a build was modelled separately, it's easy to have an explosion of different concepts that would make a build tool hard to understand.</p>
+<p>Before you continue, take a moment to think: how would you answer to each of those questions using an existing build tool you are familiar with? Different tools like <a href="http://www.scala-sbt.org/">SBT</a>, <a href="https://fake.build/legacy-index.html">Fake</a>, <a href="https://gradle.org/">Gradle</a> or <a href="https://gruntjs.com/">Grunt</a> have very different answers.</p>
+<p>Mill aims to provide the answer to these questions using as few, as familiar core concepts as possible. The entire Mill build is oriented around a few concepts:</p>
+<ul>
+ <li>The Object Hierarchy</li>
+ <li>The Call Graph</li>
+ <li>Instantiating Traits &amp; Classes</li>
+</ul>
+<p>These concepts are already familiar to anyone experienced in Scala (or any other programming language...), but are enough to answer all of the complicated build-related questions listed above.</p><h2 id="the-object-hierarchy" class="Styles-hoverBox">The Object Hierarchy<a href="#the-object-hierarchy" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>The module hierarchy is the graph of objects, starting from the root of the <code>build.sc</code> file, that extend <code>mill.Module</code>. At the leaves of the hierarchy are the <code>Target</code>s you can run.</p>
+<p>A <code>Target</code>'s position in the module hierarchy tells you many things. For example, a <code>Target</code> at position <code>core.test.compile</code> would:</p>
+<ul>
+ <li>
+ <p>Cache output metadata at <code>out/core/test/compile/meta.json</code></p></li>
+ <li>
+ <p>Output files to the folder <code>out/core/test/compile/dest/</code></p></li>
+ <li>
+ <p>Source files default to a folder in <code>core/test/</code>, <code>core/test/src/</code></p></li>
+ <li>
+ <p>Be runnable from the command-line via <code>mill core.test.compile</code></p></li>
+ <li>
+ <p>Be referenced programmatically (from other <code>Target</code>s) via <code>core.test.compile</code></p></li>
+</ul>
+<p>From the position of any <code>Target</code> within the object hierarchy, you immediately know how to run it, find its output files, find any caches, or refer to it from other <code>Target</code>s. You know up-front where the <code>Target</code>'s data "lives" on disk, and are sure that it will never clash with any other <code>Target</code>'s data.</p><h2 id="the-call-graph" class="Styles-hoverBox">The Call Graph<a href="#the-call-graph" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>The Scala call graph of "which target references which other target" is core to how Mill operates. This graph is reified via the <code>T {...}</code> macro to make it available to the Mill execution engine at runtime. The call graph tells you:</p>
+<ul>
+ <li>
+ <p>Which <code>Target</code>s depend on which other <code>Target</code>s</p></li>
+ <li>
+ <p>For a given <code>Target</code> to be built, what other <code>Target</code>s need to be run and in what order</p></li>
+ <li>
+ <p>Which <code>Target</code>s can be evaluated in parallel</p></li>
+ <li>
+ <p>What source files need to be watched when using <code>--watch</code> on a given target (by tracing the call graph up to the <code>Source</code>s)</p></li>
+ <li>
+ <p>What a given <code>Target</code> makes available for other <code>Target</code>s to depend on (via its return value)</p></li>
+ <li>
+ <p>Defining your own task that depends on others is as simple as <code>def foo =
+ T {...}</code></p></li>
+</ul>
+<p>The call graph within your Scala code is essentially a data-flow graph: by defining a snippet of code:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">val b = ...
+val c = ...
+val d = ...
+val a = f(b, c, d)
+</code></pre>
+<p>you are telling everyone that the value <code>a</code> depends on the values of <code>b</code> <code>c</code> and <code>d</code>, processed by <code>f</code>. A build tool needs exactly the same data structure: knowing what <code>Target</code> depends on what other <code>Target</code>s, and what processing it does on its inputs!</p>
+<p>With Mill, you can take the Scala call graph, wrap everything in the <code>T {...}</code> macro, and get a <code>Target</code>-dependency graph that matches exactly the call-graph you already had:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">val b = T { ... }
+val c = T { ... }
+val d = T { ... }
+val a = T { f(b(), c(), d()) }
+</code></pre>
+<p>Thus, if you are familiar with how data flows through a normal Scala program, you already know how data flows through a Mill build! The Mill build evaluation may be incremental, it may cache things, it may read and write from disk, but the fundamental syntax, and the data-flow that syntax represents, is unchanged from your normal Scala code.</p><h2 id="instantiating-traits--classes" class="Styles-hoverBox">Instantiating Traits &amp; Classes<a href="#instantiating-traits--classes" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Classes and traits are a common way of re-using common data structures in Scala: if you have a bunch of fields which are related and you want to make multiple copies of those fields, you put them in a class/trait and instantiate it over and over.</p>
+<p>In Mill, inheriting from traits is the primary way for re-using common parts of a build:</p>
+<ul>
+ <li>
+ <p>Scala "project"s with multiple related <code>Target</code>s within them, are just a <code>Trait</code> you instantiate</p></li>
+ <li>
+ <p>Replacing the default <code>Target</code>s within a project, making them do new things or depend on new <code>Target</code>s, is simply <code>override</code>-ing them during inheritance</p></li>
+ <li>
+ <p>Modifying the default <code>Target</code>s within a project, making use of the old value to compute the new value, is simply <code>override</code>ing them and using <code>super.foo()</code></p></li>
+ <li>
+ <p>Required configuration parameters within a <code>project</code> are <code>abstract</code> members</p></li>
+ <li>
+ <p>Cross-builds are modelled as instantiating a (possibly anonymous) class multiple times, each instance with its own distinct set of <code>Target</code>s</p></li>
+</ul>
+<p>In normal Scala, you bundle up common fields &amp; functionality into a <code>class</code> you can instantiate over and over, and you can override the things you want to customize. Similarly, in Mill, you bundle up common parts of a build into <code>trait</code>s you can instantiate over and over, and you can override the things you want to customize. "Subprojects", "cross-builds", and many other concepts are reduced to simply instantiating a <code>trait</code> over and over, with tweaks.</p><h2 id="prior-work" class="Styles-hoverBox">Prior Work<a href="#prior-work" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2><h3 id="sbt" class="Styles-hoverBox">SBT<a href="#sbt" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Mill is built as a substitute for SBT, whose problems are <a href="http://www.lihaoyi.com/post/SowhatswrongwithSBT.html">described here</a>. Nevertheless, Mill takes on some parts of SBT (builds written in Scala, Task graph with an Applicative "idiom bracket" macro) where it makes sense.</p><h3 id="bazel" class="Styles-hoverBox">Bazel<a href="#bazel" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Mill is largely inspired by <a href="https://bazel.build/">Bazel</a>. In particular, the single-build-hierarchy, where every Target has an on-disk-cache/output-folder according to their position in the hierarchy, comes from Bazel.</p>
+<p>Bazel is a bit odd in its own right. The underlying data model is good (hierarchy + cached dependency graph) but getting there is hell. It (like SBT) is also a 3-layer interpretation model, but layers 1 &amp; 2 are almost exactly the same: mutable python which performs global side effects (layer 3 is the same dependency-graph evaluator as SBT/mill).</p>
+<p>You end up having to deal with a non-trivial python codebase where everything happens via:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="python">do_something(name=&quot;blah&quot;)
+</code></pre>
+<p>or</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="python">do_other_thing(dependencies=[&quot;blah&quot;])
+
+</code></pre>
+<p>where <code>&quot;blah&quot;</code> is a global identifier that is often constructed programmatically via string concatenation and passed around. This is quite challenging.</p>
+<p>Having the two layers be “just python” is great since people know python, but I think unnecessary two have two layers ("evaluating macros" and "evaluating rule impls") that are almost exactly the same, and I think making them interact via return values rather than via a global namespace of programmatically-constructed strings would make it easier to follow.</p>
+<p>With Mill, I’m trying to collapse Bazel’s Python layer 1 &amp; 2 into just 1 layer of Scala, and have it define its dependency graph/hierarchy by returning values, rather than by calling global-side-effecting APIs. I've had trouble trying to teach people how-to-bazel at work, and am pretty sure we can make something that's easier to use.</p><h3 id="scalarx" class="Styles-hoverBox">Scala.Rx<a href="#scalarx" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Mill's "direct-style" applicative syntax is inspired by my old <a href="https://github.com/lihaoyi/scala.rx">Scala.Rx</a> project. While there are differences (Mill captures the dependency graph lexically using Macros, Scala.Rx captures it at runtime), they are pretty similar.</p>
+<p>The end-goal is the same: to write code in a "direct style" and have it automatically "lifted" into a dependency graph, which you can introspect and use for incremental updates at runtime.</p>
+<p>Scala.Rx is itself build upon the 2010 paper <a href="https://infoscience.epfl.ch/record/148043/files/DeprecatingObserversTR2010.pdf">Deprecating the Observer Pattern</a>.</p><h3 id="cbt" class="Styles-hoverBox">CBT<a href="#cbt" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Mill looks a lot like <a href="https://github.com/cvogt/cbt">CBT</a>. The inheritance based model for customizing <code>Module</code>s/<code>ScalaModule</code>s comes straight from there, as does the "command line path matches Scala selector path" idea. Most other things are different though: the reified dependency graph, the execution model, the caching module all follow Bazel more than they do CBT</p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="extending-mill.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Extending Mill</a><a href="contrib-modules.html">Contrib Modules <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/modules.html b/page/modules.html
new file mode 100644
index 00000000..e708f9b6
--- /dev/null
+++ b/page/modules.html
@@ -0,0 +1,221 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Modules</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#using-modules">Using Modules</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#overriding-targets">Overriding Targets</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#millsourcepath">millSourcePath</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#external-modules">External Modules</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#foreign-modules">Foreign Modules</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Modules</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="tasks.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Tasks</a><a href="cross-builds.html">Cross Builds <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><p>Mill modules are <code>object</code>s extending <code>mill.Module</code>, and let you group related tasks together to keep things neat and organized. Mill's comes with built in modules such as <code>mill.scalalib.ScalaModule</code> and <code>mill.scalalib.CrossSbtModule</code>, but you can use modules for other purposes as well.</p><h2 id="using-modules" class="Styles-hoverBox">Using Modules<a href="#using-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>The path to a Mill module from the root of your build file corresponds to the path you would use to run tasks within that module from the command line. e.g. for the following build:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Module {
+ def bar = T { &quot;hello&quot; }
+ object baz extends mill.Module {
+ def qux = T { &quot;world&quot; }
+ }
+}
+</code></pre>
+<p>You would be able to run the two targets via <code>mill foo.bar</code> or <code>mill
+foo.baz.qux</code>. You can use <code>mill show foo.bar</code> or <code>mill show foo.baz.qux</code> to make Mill echo out the string value being returned by each Target. The two targets will store their output metadata &amp; files at <code>./out/foo/bar</code> and <code>./out/foo/baz/qux</code> respectively.</p>
+<p>Modules also provide a way to define and re-use common collections of tasks, via Scala <code>trait</code>s. For example, you can define your own <code>FooModule</code> trait:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">trait FooModule extends mill.Module {
+ def bar = T { &quot;hello&quot; }
+ def baz = T { &quot;world&quot; }
+}
+</code></pre>
+<p>And use it to define multiple modules with the same <code>bar</code> and <code>baz</code> targets, along with any other customizations such as <code>qux</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo1 extends FooModule
+object foo2 extends FooModule {
+ def qux = T { &quot;I am Cow&quot; }
+}
+</code></pre>
+<p>This would make the following targets available from the command line</p>
+<ul>
+ <li><code>mill show foo1.bar</code></li>
+ <li><code>mill show foo1.baz</code></li>
+ <li><code>mill show foo2.bar</code></li>
+ <li><code>mill show foo2.baz</code></li>
+ <li><code>mill show foo2.qux</code></li>
+</ul>
+<p>The built-in <code>mill.scalalib</code> package uses this to define <code>mill.scalalib.ScalaModule</code>, <code>mill.scalalib.SbtModule</code> and <code>mill.scalalib.TestScalaModule</code>, all of which contain a set of "standard" operations such as <code>compile</code> <code>jar</code> or <code>assembly</code> that you may expect from a typical Scala module.</p>
+<p>When defining your own module abstractions, in general you should use <code>trait</code>s and not <code>class</code>es, except in the case of <a href="http://www.lihaoyi.com/mill/page/cross-builds.html">Cross Builds</a>.</p><h2 id="overriding-targets" class="Styles-hoverBox">Overriding Targets<a href="#overriding-targets" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">trait BaseModule extends Module {
+ def foo = T { Seq(&quot;base&quot;) }
+ def cmd(i: Int) = T.command { Seq(&quot;base&quot; + i) }
+}
+
+object canOverrideSuper with BaseModule {
+ def foo = T { super.foo() ++ Seq(&quot;object&quot;) }
+ def cmd(i: Int) = T.command { super.cmd(i)() ++ Seq(&quot;object&quot; + i) }
+}
+</code></pre>
+<p>You can override targets and commands to customize them or change what they do. The overriden version is available via <code>super</code>. You can omit the <code>override</code> keyword in Mill builds.</p><h2 id="millsourcepath" class="Styles-hoverBox">millSourcePath<a href="#millsourcepath" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Each Module has a <code>millSourcePath</code> field that corresponds to the path that module expects its input files to be on disk. Re-visiting our examples above:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Module {
+ def bar = T { &quot;hello&quot; }
+ object baz extends mill.Module {
+ def qux = T { &quot;world&quot; }
+ }
+}
+</code></pre>
+<p>The <code>foo</code> module has a <code>millSourcePath</code> of <code>./foo</code>, while the <code>foo.baz</code> module has a <code>millSourcePath</code> of <code>./foo/baz</code>.</p>
+<p>You can use <code>millSourcePath</code> to automatically set the source folders of your modules to match the build structure. You are not forced to rigidly use <code>millSourcePath</code> to define the source folders of all your code, but it can simplify the common case where you probably want your build-layout and on-disk-layout to be the same.</p>
+<p>E.g. for <code>mill.scalalib.ScalaModule</code>, the Scala source code is assumed by default to be in <code>millSourcePath/&quot;src&quot;</code> while resources are automatically assumed to be in <code>millSourcePath/&quot;resources&quot;</code>.</p>
+<p>You can override <code>millSourcePath</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object foo extends mill.Module {
+ def millSourcePath = super.millSourcePath / &quot;lols&quot;
+ def bar = T { &quot;hello&quot; }
+ object baz extends mill.Module {
+ def qux = T { &quot;world&quot; }
+ }
+}
+</code></pre>
+<p>And any overrides propagate down to the module's children: in the above example, module <code>foo</code> would have its <code>millSourcePath</code> be <code>./foo/lols</code> while module<code>foo.baz</code> would have its <code>millSourcePath</code> be <code>./foo/lols/baz</code>.</p>
+<p>Note that <code>millSourcePath</code> is generally only used for a module's input source files. Output is always in the <code>out/</code> folder and cannot be changed, e.g. even with the overriden <code>millSourcePath</code> the output paths are still the default <code>./out/foo/bar</code> and <code>./out/foo/baz/qux</code> folders.</p><h2 id="external-modules" class="Styles-hoverBox">External Modules<a href="#external-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Libraries for use in Mill can define <code>ExternalModule</code>s: <code>Module</code>s which are shared between all builds which use that library:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">package foo
+import mill._
+
+object Bar extends mill.define.ExternalModule {
+ def baz = T { 1 }
+ def qux() = T.command { println(baz() + 1) }
+
+ lazy val millDiscover = mill.define.Discover[this.type]
+}
+</code></pre>
+<p>In the above example, <code>foo.Bar</code> is an <code>ExternalModule</code> living within the <code>foo</code> Java package, containing the <code>baz</code> target and <code>qux</code> command. Those can be run from the command line via:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">mill foo.Bar/baz
+mill foo.Bar/qux
+</code></pre>
+<p><code>ExternalModule</code>s are useful for someone providing a library for use with Mill that is shared by the entire build: for example, <code>mill.scalalib.ZincWorkerApi/zincWorker</code> provides a shared Scala compilation service &amp; cache that is shared between all <code>ScalaModule</code>s, and <code>mill.scalalib.GenIdea/idea</code> lets you generate IntelliJ projects without needing to define your own <code>T.command</code> in your <code>build.sc</code> file</p><h2 id="foreign-modules" class="Styles-hoverBox">Foreign Modules<a href="#foreign-modules" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Mill can load other mill projects from external (or sub) folders, using Ammonite's <code>$file</code> magic import, allowing to depend on foreign modules. This allows, for instance, to depend on other projects' sources, or split your build logic into smaller files.</p>
+<p>For instance, assuming the following stucture : </p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">foo/
+ build.sc
+ bar/
+ build.sc
+baz/
+ build.sc
+</code></pre>
+<p>you can write the following in <code>foo/build.sc</code> : </p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">
+import $file.bar.build
+import $file.^.baz.build
+import mill._
+
+def someFoo = T {
+
+ ^.baz.build.someBaz(...)
+ bar.build.someBar(...)
+ ...
+}
+</code></pre>
+<p>The output of the foreign tasks will be cached under <code>foo/out/foreign-modules/</code>. </p><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="tasks.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Tasks</a><a href="cross-builds.html">Cross Builds <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/tasks.html b/page/tasks.html
new file mode 100644
index 00000000..864870f7
--- /dev/null
+++ b/page/tasks.html
@@ -0,0 +1,324 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Tasks</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#different-kinds-of-tasks">Different Kinds of Tasks</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#targets">Targets</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#sources">Sources</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#commands">Commands</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#task-context-api">Task Context API</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#millapictxdest">mill.api.Ctx.Dest</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#millapictxlog">mill.api.Ctx.Log</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#millapictxenv">mill.api.Ctx.Env</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#other-tasks">Other Tasks</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#anonymous-tasks">Anonymous Tasks</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#persistent-targets">Persistent Targets</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#inputs">Inputs</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#workers">Workers</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#cheat-sheet">Cheat Sheet</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Tasks</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="common-project-layouts.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Common Project Layouts</a><a href="modules.html">Modules <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div><p>One of Mill's core abstractions is its <em>Task Graph</em>: this is how Mill defines, orders and caches work it needs to do, and exists independently of any support for building Scala.</p>
+<p>The following is a simple self-contained example using Mill to compile Java:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">, mill._
+
+// sourceRoot -&gt; allSources -&gt; classFiles
+// |
+// v
+// resourceRoot ----&gt; jar
+
+def sourceRoot = T.sources { os.pwd / &#39;src }
+
+def resourceRoot = T.sources { os.pwd / &#39;resources }
+
+def allSources = T { sourceRoot().flatMap(p =&gt; os.walk(p.path)).map(PathRef(_)) }
+
+def classFiles = T {
+ os.makeDir.all(T.ctx().dest)
+
+ %(&quot;javac&quot;, allSources().map(_.path.toString()), &quot;-d&quot;, T.ctx().dest)(wd = T.ctx().dest)
+ PathRef(T.ctx().dest)
+}
+
+def jar = T { Jvm.createJar(Loose.Agg(classFiles().path) ++ resourceRoot().map(_.path)) }
+
+def run(mainClsName: String) = T.command {
+ os.proc(&#39;java, &quot;-cp&quot;, classFiles().path, mainClsName).call()
+}
+</code></pre>
+<p>Here, we have two <code>T.sources</code>s, <code>sourceRoot</code> and <code>resourceRoot</code>, which act as the roots of our task graph. <code>allSources</code> depends on <code>sourceRoot</code> by calling <code>sourceRoot()</code> to extract its value, <code>classFiles</code> depends on <code>allSources</code> the same way, and <code>jar</code> depends on both <code>classFiles</code> and <code>resourceRoot</code>.</p>
+<p>Filesystem operations in Mill are done using the <a href="http://ammonite.io/#Ammonite-Ops">Ammonite-Ops</a> library.</p>
+<p>The above build defines the following task graph:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">sourceRoot -&gt; allSources -&gt; classFiles
+ |
+ v
+ resourceRoot ----&gt; jar
+</code></pre>
+<p>When you first evaluate <code>jar</code> (e.g. via <code>mill jar</code> at the command line), it will evaluate all the defined targets: <code>sourceRoot</code>, <code>allSources</code>, <code>classFiles</code>, <code>resourceRoot</code> and <code>jar</code>.</p>
+<p>Subsequent <code>mill jar</code>s will evaluate only as much as is necessary, depending on what input sources changed:</p>
+<ul>
+ <li>
+ <p>If the files in <code>sourceRoot</code> change, it will re-evaluate <code>allSources</code>, compiling to <code>classFiles</code>, and building the <code>jar</code></p></li>
+ <li>
+ <p>If the files in <code>resourceRoot</code> change, it will only re-evaluate <code>jar</code> and use the cached output of <code>allSources</code> and <code>classFiles</code></p></li>
+</ul>
+<p>Apart from the <code>foo()</code> call-sites which define what each targets depend on, the code within each <code>T {...}</code> wrapper is arbitrary Scala code that can compute an arbitrary result from its inputs.</p><h2 id="different-kinds-of-tasks" class="Styles-hoverBox">Different Kinds of Tasks<a href="#different-kinds-of-tasks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>There are three primary kinds of <em>Tasks</em> that you should care about:</p>
+<ul>
+ <li><a href="#targets">Targets</a>, defined using <code>T {...}</code></li>
+ <li><a href="#sources">Sources</a>, defined using <code>T.sources {...}</code></li>
+ <li><a href="#commands">Commands</a>, defined using <code>T.command {...}</code></li>
+</ul><h3 id="targets" class="Styles-hoverBox">Targets<a href="#targets" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def allSources = T { os.walk(sourceRoot().path).map(PathRef(_)) }
+</code></pre>
+<p><code>Target</code>s are defined using the <code>def foo = T {...}</code> syntax, and dependencies on other targets are defined using <code>foo()</code> to extract the value from them. Apart from the <code>foo()</code> calls, the <code>T {...}</code> block contains arbitrary code that does some work and returns a result.</p>
+<p>Each target, e.g. <code>classFiles</code>, is assigned a path on disk as scratch space &amp; to store its output files at <code>out/classFiles/dest/</code>, and its returned metadata is automatically JSON-serialized and stored at <code>out/classFiles/meta.json</code>. The return-value of targets has to be JSON-serializable via <a href="https://github.com/lihaoyi/upickle">uPickle</a>.</p>
+<p>In case you want return your own case class (e.g. <code>MyCaseClass</code>), you can make it JSON-serializable by adding the following implicit def to its companion object:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">object MyCaseClass {
+ implicit def rw: upickle.default.ReadWriter[MyCaseClass] = upickle.default.macroRW
+}
+</code></pre>
+<p>If you want to return a file or a set of files as the result of a <code>Target</code>, write them to disk within your <code>T.ctx().dest</code> available through the <a href="#task-context-api">Task Context API</a> and return a <code>PathRef</code> to the files you wrote.</p>
+<p>If a target's inputs change but its output does not, e.g. someone changes a comment within the source files that doesn't affect the classfiles, then downstream targets do not re-evaluate. This is determined using the <code>.hashCode</code> of the Target's return value. For targets returning <code>ammonite.ops.Path</code>s that reference files on disk, you can wrap the <code>Path</code> in a <code>PathRef</code> (shown above) whose <code>.hashCode()</code> will include the hashes of all files on disk at time of creation.</p>
+<p>The graph of inter-dependent targets is evaluated in topological order; that means that the body of a target will not even begin to evaluate if one of its upstream dependencies has failed. This is unlike normal Scala functions: a plain old function <code>foo</code> would evaluate halfway and then blow up if one of <code>foo</code>'s dependencies throws an exception.</p>
+<p>Targets cannot take parameters and must be 0-argument <code>def</code>s defined directly within a <code>Module</code> body.</p><h3 id="sources" class="Styles-hoverBox">Sources<a href="#sources" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def sourceRootPath = os.pwd / &#39;src
+
+def sourceRoots = T.sources { sourceRootPath }
+</code></pre>
+<p><code>Source</code>s are defined using <code>T.sources { ... }</code>, taking one-or-more <code>ammonite.ops.Path</code>s as arguments. A <code>Source</code> is a subclass of <code>Target[Seq[PathRef]]</code>: this means that its build signature/<code>hashCode</code> depends not just on the path it refers to (e.g. <code>foo/bar/baz</code>) but also the MD5 hash of the filesystem tree under that path.</p>
+<p><code>T.sources</code> also has an overload which takes <code>Seq[PathRef]</code>, to let you override-and-extend source lists the same way you would any other <code>T {...}</code> definition:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def additionalSources = T.sources { os.pwd / &#39;additionalSources }
+def sourceRoots = T.sources { super.sourceRoots() ++ additionalSources() }
+</code></pre><h3 id="commands" class="Styles-hoverBox">Commands<a href="#commands" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def run(mainClsName: String) = T.command {
+ os.proc(&#39;java, &quot;-cp&quot;, classFiles().path, mainClsName).call()
+}
+</code></pre>
+<p>Defined using <code>T.command { ... }</code> syntax, <code>Command</code>s can run arbitrary code, with dependencies declared using the same <code>foo()</code> syntax (e.g. <code>classFiles()</code> above). Commands can be parametrized, but their output is not cached, so they will re-evaluate every time even if none of their inputs have changed.</p>
+<p>Like <a href="#targets">Targets</a>, a command only evaluates after all its upstream dependencies have completed, and will not begin to run if any upstream dependency has failed.</p>
+<p>Commands are assigned the same scratch/output folder <code>out/run/dest/</code> as Targets are, and its returned metadata stored at the same <code>out/run/meta.json</code> path for consumption by external tools.</p>
+<p>Commands can only be defined directly within a <code>Module</code> body.</p><h2 id="task-context-api" class="Styles-hoverBox">Task Context API<a href="#task-context-api" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>There are several APIs available to you within the body of a <code>T {...}</code> or <code>T.command {...}</code> block to help your write the code implementing your Target or Command:</p><h3 id="millapictxdest" class="Styles-hoverBox">mill.api.Ctx.Dest<a href="#millapictxdest" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><code>T.ctx().dest</code></li>
+ <li><code>implicitly[mill.api.Ctx.Dest]</code></li>
+</ul>
+<p>This is the unique <code>out/classFiles/dest/</code> path or <code>out/run/dest/</code> path that is assigned to every Target or Command. It is cleared before your task runs, and you can use it as a scratch space for temporary files or a place to put returned artifacts. This is guaranteed to be unique for every <code>Target</code> or <code>Command</code>, so you can be sure that you will not collide or interfere with anyone else writing to those same paths.</p><h3 id="millapictxlog" class="Styles-hoverBox">mill.api.Ctx.Log<a href="#millapictxlog" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><code>T.ctx().log</code></li>
+ <li><code>implicitly[mill.api.Ctx.Log]</code></li>
+</ul>
+<p>This is the default logger provided for every task. While your task is running, <code>System.out</code> and <code>System.in</code> are also redirected to this logger. The logs for a task are streamed to standard out/error as you would expect, but each task's specific output is also streamed to a log file on disk, e.g. <code>out/run/log</code> or <code>out/classFiles/log</code> for you to inspect later.</p>
+<p>Messages logged with <code>log.debug</code> appear by default only in the log files. You can use the <code>--debug</code> option when running mill to show them on the console too.</p><h3 id="millapictxenv" class="Styles-hoverBox">mill.api.Ctx.Env<a href="#millapictxenv" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li><code>T.ctx().env</code></li>
+ <li><code>implicitly[mill.api.Ctx.Env]</code></li>
+</ul>
+<p>Mill keeps a long-lived JVM server to avoid paying the cost of recurrent classloading. Because of this, running <code>System.getenv</code> in a task might not yield up to date environment variables, since it will be initialised when the server starts, rather than when the client executes. To circumvent this, mill's client sends the environment variables to the server as it sees them, and the server makes them available as a <code>Map[String, String]</code> via the <code>Ctx</code> API. </p>
+<p>If the intent is to always pull the latest environment values, the call should be wrapped in an <code>Input</code> as such : </p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def envVar = T.input { T.ctx().env.get(&quot;ENV_VAR&quot;) }
+</code></pre><h2 id="other-tasks" class="Styles-hoverBox">Other Tasks<a href="#other-tasks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<ul>
+ <li><a href="#anonymous-tasks">Anonymous Tasks</a>, defined using <code>T.task {...}</code></li>
+ <li><a href="#persistent-targets">Persistent Targets</a></li>
+ <li><a href="#inputs">Inputs</a></li>
+ <li><a href="#workers">Workers</a></li>
+</ul><h3 id="anonymous-tasks" class="Styles-hoverBox">Anonymous Tasks<a href="#anonymous-tasks" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def foo(x: Int) = T.task { ... x ... bar() ... }
+</code></pre>
+<p>You can define anonymous tasks using the <code>T.task { ... }</code> syntax. These are not runnable from the command-line, but can be used to share common code you find yourself repeating in <code>Target</code>s and <code>Command</code>s.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def downstreamTarget = T { ... foo() ... }
+def downstreamCommand = T.command { ... foo() ... }
+</code></pre>
+<p>Anonymous task's output does not need to be JSON-serializable, their output is not cached, and they can be defined with or without arguments. Unlike <a href="#targets">Targets</a> or <a href="#commands">Commands</a>, anonymous tasks can be defined anywhere and passed around any way you want, until you finally make use of them within a downstream target or command.</p>
+<p>While an anonymous task <code>foo</code>'s own output is not cached, if it is used in a downstream target <code>bar</code> and the upstream targets <code>baz</code> <code>qux</code> haven't changed, <code>bar</code>'s cached output will be used and <code>foo</code>'s evaluation will be skipped altogether.</p><h3 id="persistent-targets" class="Styles-hoverBox">Persistent Targets<a href="#persistent-targets" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def foo = T.persistent { ... }
+</code></pre>
+<p>Identical to <a href="#targets">Targets</a>, except that the <code>dest/</code> folder is not cleared in between runs.</p>
+<p>This is useful if you are running external incremental-compilers, such as Scala's <a href="https://github.com/sbt/zinc">Zinc</a>, Javascript's <a href="https://webpack.js.org/">WebPack</a>, which rely on filesystem caches to speed up incremental execution of their particular build step.</p>
+<p>Since Mill no longer forces a "clean slate" re-evaluation of <code>T.persistent</code> targets, it is up to you to ensure your code (or the third-party incremental compilers you rely on!) are deterministic. They should always converge to the same outputs for a given set of inputs, regardless of what builds and what filesystem states existed before.</p><h3 id="inputs" class="Styles-hoverBox">Inputs<a href="#inputs" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def foo = T.input { ... }
+</code></pre>
+<p>A generalization of <a href="#sources">Sources</a>, <code>T.input</code>s are tasks that re-evaluate <em>every time</em> (unlike <a href="#anonymous-tasks">Anonymous Tasks</a>), containing an arbitrary block of code.</p>
+<p>Inputs can be used to force re-evaluation of some external property that may affect your build. For example, if I have a <a href="#targets">Target</a> <code>bar</code> that makes use of the current git version:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def bar = T { ... os.proc(&quot;git&quot;, &quot;rev-parse&quot;, &quot;HEAD&quot;).call().out.string ... }
+</code></pre>
+<p><code>bar</code> will not know that <code>git rev-parse</code> can change, and will not know to re-evaluate when your <code>git rev-parse HEAD</code> <em>does</em> change. This means <code>bar</code> will continue to use any previously cached value, and <code>bar</code>'s output will be out of date!</p>
+<p>To fix this, you can wrap your <code>git rev-parse HEAD</code> in a <code>T.input</code>:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def foo = T.input { os.proc(&quot;git&quot;, &quot;rev-parse&quot;, &quot;HEAD&quot;).call().out.string }
+def bar = T { ... foo() ... }
+</code></pre>
+<p>This makes <code>foo</code> will always re-evaluate every build; if <code>git rev-parse HEAD</code> does not change, that will not invalidate <code>bar</code>'s caches. But if <code>git rev-parse
+HEAD</code> <em>does</em> change, <code>foo</code>'s output will change and <code>bar</code> will be correctly invalidated and re-compute using the new version of <code>foo</code>.</p>
+<p>Note that because <code>T.input</code>s re-evaluate every time, you should ensure that the code you put in <code>T.input</code> runs quickly. Ideally it should just be a simple check "did anything change?" and any heavy-lifting can be delegated to downstream targets.</p><h3 id="workers" class="Styles-hoverBox">Workers<a href="#workers" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">def foo = T.worker { ... }
+</code></pre>
+<p>Most tasks dispose of their in-memory return-value every evaluation; in the case of <a href="#targets">Targets</a>, this is stored on disk and loaded next time if necessary, while <a href="#commands">Commands</a> just re-compute them each time. Even if you use <code>--watch</code> or the Build REPL to keep the Mill process running, all this state is still discarded and re-built every evaluation.</p>
+<p>Workers are unique in that they store their in-memory return-value between evaluations. This makes them useful for storing in-memory caches or references to long-lived external worker processes that you can re-use.</p>
+<p>Mill uses workers to manage long-lived instances of the <a href="https://github.com/sbt/zinc">Zinc Incremental Scala Compiler</a> and the <a href="https://github.com/scala-js/scala-js">Scala.js Optimizer</a>. This lets us keep them in-memory with warm caches and fast incremental execution.</p>
+<p>Like <a href="#persistent-targets">Persistent Targets</a>, Workers inherently involve mutable state, and it is up to the implementation to ensure that this mutable state is only used for caching/performance and does not affect the externally-visible behavior of the worker.</p><h2 id="cheat-sheet" class="Styles-hoverBox">Cheat Sheet<a href="#cheat-sheet" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>The following table might help you make sense of the small collection of different Task types:</p><table class="table table-bordered">
+<thead>
+ <tr>
+ <th align="left"> </th>
+ <th align="left">Target </th>
+ <th align="left">Command </th>
+ <th align="left">Source/Input </th>
+ <th align="left">Anonymous Task </th>
+ <th align="left">Persistent Target </th>
+ <th align="left">Worker </th>
+ </tr>
+</thead>
+<tbody>
+ <tr>
+ <td align="left">Cached on Disk </td>
+ <td align="left">X </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ </tr>
+ <tr>
+ <td align="left">Must be JSON Writable </td>
+ <td align="left">X </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ </tr>
+ <tr>
+ <td align="left">Must be JSON Readable </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ </tr>
+ <tr>
+ <td align="left">Runnable from the Command Line </td>
+ <td align="left">X </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ </tr>
+ <tr>
+ <td align="left">Can Take Arguments </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ </tr>
+ <tr>
+ <td align="left">Cached between Evaluations </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left"> </td>
+ <td align="left">X </td>
+ </tr>
+</tbody></table><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="common-project-layouts.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Common Project Layouts</a><a href="modules.html">Modules <i class="fa fa-arrow-right" aria-hidden="true"></i></a></div></div></body></html> \ No newline at end of file
diff --git a/page/thirdparty-modules.html b/page/thirdparty-modules.html
new file mode 100644
index 00000000..52c8839f
--- /dev/null
+++ b/page/thirdparty-modules.html
@@ -0,0 +1,351 @@
+<html><head><meta charset="utf-8" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" /><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /><link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" rel="stylesheet" type="text/css" /><title>Thirdparty Modules</title><style>@media (min-width: 60em) {.WideStyles-header{
+ bottom: 0px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ position: fixed;
+ top: 0px;
+ width: 25%;
+}
+
+.WideStyles-tableOfContentsItem{
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ width: 100%;
+}
+
+.WideStyles-tableOfContents{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 0px;
+ width: 100%;
+}
+
+.WideStyles-content{
+ box-sizing: border-box;
+ margin-left: 25%;
+ padding: 48px;
+}
+
+.WideStyles-footer{
+ bottom: 0px;
+ height: 50px;
+ position: fixed;
+ width: 25%;
+}
+
+.WideStyles-marginLeftZero{
+ margin-left: 0px;
+}
+}</style><style>@media (max-width: 60em) {.NarrowStyles-header{
+ margin-bottom: 10px;
+}
+
+.NarrowStyles-content{
+ padding: 16px;
+}
+
+.NarrowStyles-headerContent{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+
+.NarrowStyles-flexFont{
+ font-size: 4vw;
+}
+
+.NarrowStyles-disappear{
+ display: none;
+}
+
+.NarrowStyles-floatLeft{
+ float: left;
+ margin-left: 30px;
+}
+}</style><style>.Styles-hoverBox{
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.Styles-hoverBox:hover .Styles-hoverLink{
+ opacity: 0.5;
+}
+
+.Styles-hoverLink{
+ opacity: 0.1;
+}
+.Styles-hoverLink:hover{
+ opacity: 1.0;
+}
+
+.Styles-headerStyle{
+ background-color: rgb(61, 79, 93);
+ box-sizing: border-box;
+ display: flex;
+}
+
+.Styles-headerLinkBox{
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.Styles-headerLink{
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ padding: 10px 10px;
+}
+
+.Styles-footerStyle{
+ color: rgb(158, 167, 174);
+ display: flex;
+ justify-content: center;
+}
+
+.Styles-subtleLink{
+ text-decoration: none;
+}
+</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"></script><script>hljs.initHighlightingOnLoad();</script><meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" /></head><body style="margin: 0px;background-color: #f8f8f8;"><div class=" WideStyles-header NarrowStyles-header Styles-headerStyle"><div class=" NarrowStyles-headerContent"><h1 style="text-align: center;padding: 30px 30px;margin: 0px;"><a style="color: #f8f8f8;font-weight: bold;" href=".." class=" Styles-subtleLink NarrowStyles-flexFont"><img src="../logo-white.svg" style="height: 30px;margin-top: -5px;" /> Mill</a></h1><div class=" Styles-headerLinkBox"><div class=" WideStyles-tableOfContents" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Pages</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="../index.html">Intro to Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="configuring-mill.html">Configuring Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="common-project-layouts.html">Common Project Layouts</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="tasks.html">Tasks</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="modules.html">Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="cross-builds.html">Cross Builds</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="extending-mill.html">Extending Mill</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="mill-internals.html">Mill Internals</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="contrib-modules.html">Contrib Modules</a></li><li class=" WideStyles-marginLeftZero NarrowStyles-floatLeft"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="thirdparty-modules.html">Thirdparty Modules</a></li></ul></div></div></div></div><hr class=" NarrowStyles-disappear" style="background-color: #f8f8f8;width: 80%;" /><div class=" WideStyles-tableOfContents NarrowStyles-disappear" style="color: #f8f8f8;"><div style="padding-left: 40px;" class=" NarrowStyles-disappear"><b>Table of Contents</b></div><div style="overflow-y: auto;flex-shrink: 1;min-height: 0px;"><ul style="overflow: hidden;text-align: start;margin-top: 10px;white-space: nowrap;text-overflow: ellipsis;margin-right: 10px;"><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#aspectj">AspectJ</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration">Configuration</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#bash-completion">Bash Completion</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#dgraph">DGraph</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#ensime">Ensime</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#integration-testing-mill-plugins">Integration Testing Mill Plugins</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration-and-targets">Configuration and Targets</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#jbake">JBake</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#jbuildinfo">JBuildInfo</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#configuration-options">Configuration options</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#mill-wrapper-scripts">Mill Wrapper Scripts</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#how-it-works">How it works</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#use-cases">Use cases</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#osgi">OSGi</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li><li style="margin-left: 0px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#publishm2">PublishM2</a></li><li style="margin-left: 20px;"><a style="color: #f8f8f8;" class=" WideStyles-tableOfContentsItem" href="#quickstart">Quickstart</a></li></ul></div></div></div><div class=" WideStyles-content NarrowStyles-content" style="max-width: 900px;"><h1>Thirdparty Modules</h1><div style="margin-bottom: 10px;"><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="contrib-modules.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Contrib Modules</a><div></div></div></div><p>The modules (aka plugins) in this section are developed/maintained outside the mill git tree.</p>
+<p>Besides the documentation provided here, we urge you to consult the respective linked plugin documentation pages. The usage examples given here are most probably incomplete and sometimes outdated.</p>
+<p>If you develop or maintain a mill plugin, please create a <a href="https://github.com/lihaoyi/mill/pulls">pull request</a> to get your plugin listed here.</p><h2 id="aspectj" class="Styles-hoverBox">AspectJ<a href="#aspectj" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p><a href="https://projects.eclipse.org/projects/tools.aspectj">AspectJ compiler</a> support for mill.</p>
+<p>Project home: <a href="https://github.com/lefou/mill-aspectj">https://github.com/lefou/mill-aspectj</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._
+import mill.scalalib._
+import mill.define._
+
+// Load the plugin from Maven Central via ivy/coursier
+import $ivy.`de.tototec::de.tobiasroeser.mill.aspectj:0.1.0`, de.tobiasroeser.mill.aspectj._
+
+object main extends AspectjModule {
+
+ // Select the AspectJ version
+ def aspectjVersion = T{ &quot;{aspectjVersion}&quot; }
+
+ // Set AspectJ options, e.g. the language level and annotation processor
+ // Run `mill main.ajcHelp` to get a list of supported options
+ def ajcOptions = Seq(&quot;-8&quot;, &quot;-proc:none&quot;)
+
+}
+</code></pre><h3 id="configuration" class="Styles-hoverBox">Configuration<a href="#configuration" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Your module needs to extend <code>de.tobiasroeser.mill.aspectj.AspectjModule</code> which itself extends <code>mill.scalalib.JavaModule</code>.</p>
+<p>The module trait <code>de.tobiasroeser.mill.aspectj.AspectjModule</code> has various configuration options (over those from <code>mill.scalalib.JavaModule</code>).</p>
+<p>The most essential targets are:</p>
+<ul>
+ <li>
+ <p><code>def aspectjVersion: T[String]</code> - The AspectJ version. <em>Required</em>. For a list of available releases refer to the <a href="https://www.eclipse.org/aspectj/downloads.php">AspectJ Download Page</a>.</p></li>
+ <li>
+ <p><code>def ajcOptions: T[Seq[String]]</code> - Additional options to be used by <code>ajc</code> in the <code>compile</code> target.</p></li>
+ <li>
+ <p><code>def compile: T[CompilationResult]</code> - Compiles the source code with the ajc compiler.</p></li>
+</ul>
+<p>For a complete list of configuration options and more documentation, please refer to the <a href="https://github.com/lefou/mill-aspectj">project home page</a>.</p><h2 id="bash-completion" class="Styles-hoverBox">Bash Completion<a href="#bash-completion" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Limited bash completion support.</p>
+<p>Project home: <a href="https://github.com/lefou/mill-bash-completion">https://github.com/lefou/mill-bash-completion</a></p><h2 id="dgraph" class="Styles-hoverBox">DGraph<a href="#dgraph" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Show transitive dependencies of your build in your browser.</p>
+<p>Project home: <a href="https://github.com/ajrnz/mill-dgraph">https://github.com/ajrnz/mill-dgraph</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import $ivy.`com.github.ajrnz::mill-dgraph:0.2.0`
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="sh">sh&gt; mill plugin.dgraph.browseDeps(proj)()
+</code></pre><h2 id="ensime" class="Styles-hoverBox">Ensime<a href="#ensime" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Create an <a href="http://ensime.github.io/" title="ensime">.ensime</a> file for your build.</p>
+<p>Project home: <a href="https://github.com/yyadavalli/mill-ensime">https://github.com/yyadavalli/mill-ensime</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import $ivy.`fun.valycorp::mill-ensime:0.0.1`
+</code></pre>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="sh">sh&gt; mill fun.valycorp.mill.GenEnsime/ensimeConfig
+</code></pre><h2 id="integration-testing-mill-plugins" class="Styles-hoverBox">Integration Testing Mill Plugins<a href="#integration-testing-mill-plugins" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Integration testing for mill plugins.</p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>We assume, you have a mill plugin named <code>mill-demo</code></p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._, mill.scalalib._
+object demo extends ScalaModule with PublishModule {
+ // ...
+}
+</code></pre>
+<p>Add an new test sub-project, e.g. <code>it</code>.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import $ivy.`de.tototec::de.tobiasroeser.mill.integrationtest:0.1.0`
+import de.tobiasroeser.mill.integrationtest._
+
+object it extends MillIntegrationTest {
+
+ def millTestVersion = &quot;{exampleMillVersion}&quot;
+
+ def pluginsUnderTest = Seq(demo)
+
+}
+</code></pre>
+<p>Your project should now look similar to this:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="text">.
++-- demo/
+| +-- src/
+|
++-- it/
+ +-- src/
+ +-- 01-first-test/
+ | +-- build.sc
+ | +-- src/
+ |
+ +-- 02-second-test/
+ +-- build.sc
+</code></pre>
+<p>As the buildfiles <code>build.sc</code> in your test cases typically want to access the locally built plugin(s), the plugins publishes all plugins referenced under <code>pluginsUnderTest</code> to a temporary ivy repository, just before the test is executed. The mill version used in the integration test then used that temporary ivy repository.</p>
+<p>Instead of referring to your plugin with <code>import $ivy.&#39;your::plugin:version&#39;</code>, you can use the following line instead, which ensures you will use the correct locally build plugins.</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import $exec.plugins
+</code></pre>
+<p>Effectively, at execution time, this line gets replaced by the content of <code>plugins.sc</code>, a file which was generated just before the test started to execute.</p><h3 id="configuration-and-targets" class="Styles-hoverBox">Configuration and Targets<a href="#configuration-and-targets" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>The mill-integrationtest plugin provides the following targets.</p><h4 id="mandatory-configuration" class="Styles-hoverBox">Mandatory configuration<a href="#mandatory-configuration" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h4>
+<ul>
+ <li>
+ <p><code>def millTestVersion: T[String]</code> The mill version used for executing the test cases. Used by <code>downloadMillTestVersion</code> to automatically download.</p></li>
+ <li>
+ <p><code>def pluginsUnderTest: Seq[PublishModule]</code> - The plugins used in the integration test. You should at least add your plugin under test here. You can also add additional libraries, e.g. those that assist you in the test result validation (e.g. a local test support project). The defined modules will be published into a temporary ivy repository before the tests are executed. In your test <code>build.sc</code> file, instead of the typical <code>import $ivy.</code> line, you should use <code>import $exec.plugins</code> to include all plugins that are defined here.</p></li>
+</ul><h4 id="optional-configuration" class="Styles-hoverBox">Optional configuration<a href="#optional-configuration" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h4>
+<ul>
+ <li>
+ <p><code>def sources: Sources</code> - Locations where integration tests are located. Each integration test is a sub-directory, containing a complete test mill project.</p></li>
+ <li>
+ <p><code>def testCases: T[Seq[PathRef]]</code> - The directories each representing a mill test case. Derived from <code>sources</code>.</p></li>
+ <li>
+ <p><code>def testTargets: T[Seq[String]]</code> - The targets which are called to test the project. Defaults to <code>verify</code>, which should implement test result validation.</p></li>
+ <li>
+ <p><code>def downloadMillTestVersion: T[PathRef]</code> - Download the mill version as defined by <code>millTestVersion</code>. Override this, if you need to use a custom built mill version. Returns the <code>PathRef</code> to the mill executable (must have the executable flag).</p></li>
+</ul><h4 id="commands" class="Styles-hoverBox">Commands<a href="#commands" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h4>
+<ul>
+ <li><code>def test(): Command[Unit]</code> - Run the integration tests.</li>
+</ul><h2 id="jbake" class="Styles-hoverBox">JBake<a href="#jbake" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Create static sites/blogs with JBake.</p>
+<p>Plugin home: <a href="https://github.com/lefou/mill-jbake">https://github.com/lefou/mill-jbake</a></p>
+<p>JBake home: <a href="https://jbake.org">https://jbake.org</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import mill._
+import $ivy.`de.tototec::de.tobiasroeser.mill.jbake:0.1.0`
+import de.tobiasroeser.mill.jbake._
+
+object site extends JBakeModule {
+
+ def jbakeVersion = &quot;2.6.4&quot;
+
+}
+</code></pre>
+<p>Generate the site:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="sh">bash&gt; mill site.jbake
+</code></pre>
+<p>Start a local Web-Server on Port 8820 with the generated site:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="sh">bash&gt; mill site.jbakeServe
+</code></pre><h2 id="jbuildinfo" class="Styles-hoverBox">JBuildInfo<a href="#jbuildinfo" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>This is a <a href="https://www.lihaoyi.com/mill/">mill</a> module similar to <a href="https://www.lihaoyi.com/mill/page/contrib-modules.html#buildinfo">BuildInfo</a> but for Java. It will generate a Java class containing information from your build.</p>
+<p>Project home: <a href="https://github.com/carueda/mill-jbuildinfo">https://github.com/carueda/mill-jbuildinfo</a></p>
+<p>To declare a module that uses this plugin, extend the <code>com.github.carueda.mill.JBuildInfo</code> trait and provide the desired information via the <code>buildInfoMembers</code> method:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">// build.sc
+import $ivy.`com.github.carueda::jbuildinfo:0.1.2`
+import com.github.carueda.mill.JBuildInfo
+import mill.T
+
+object project extends JBuildInfo {
+ def buildInfoMembers: T[Map[String, String]] = T {
+ Map(
+ &quot;name&quot; -&gt; &quot;some name&quot;,
+ &quot;version&quot; -&gt; &quot;x.y.z&quot;
+ )
+ }
+}
+</code></pre>
+<p>This will generate:</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="java">// BuildInfo.java
+public class BuildInfo {
+ public static final String getName() { return &quot;some name&quot;; }
+ public static final String getVersion() { return &quot;x.y.z&quot;; }
+}
+</code></pre><h3 id="configuration-options" class="Styles-hoverBox">Configuration options<a href="#configuration-options" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<ul>
+ <li>
+ <p><code>def buildInfoMembers: T[Map[String, String]]</code></p>
+ <p>The map containing all member names and values for the generated class.</p>
+ </li>
+ <li>
+ <p><code>def buildInfoClassName: String</code>, default: <code>BuildInfo</code></p>
+ <p>The name of the class that will contain all the members from <code>buildInfoMembers</code>.</p>
+ </li>
+ <li>
+ <p><code>def buildInfoPackageName: Option[String]</code>, default: <code>None</code></p>
+ <p>The package name for the generated class.</p>
+ </li>
+</ul><h2 id="mill-wrapper-scripts" class="Styles-hoverBox">Mill Wrapper Scripts<a href="#mill-wrapper-scripts" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Small script to automatically fetch and execute mill build tool.</p>
+<p>Project home: <a href="https://github.com/lefou/millw">https://github.com/lefou/millw</a></p><h3 id="how-it-works" class="Styles-hoverBox">How it works<a href="#how-it-works" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p><code>millw</code> is a small wrapper script around mill and works almost identical to mill. It automatically downloads a mill release into <code>$HOME/.mill/download</code>.</p>
+<p>The mill version to be used will be determined by the following steps. The search ends, after the first step that results in a version.</p>
+<ul>
+ <li>If the first parameter is <code>--mill-version</code>, the second parameter will be used as the mill version. Example</li>
+</ul>
+<p><code>
+ sh $ mill --mill-version 0.3.6 --disable-ticker version
+ 0.3.6
+</code></p>
+<ul>
+ <li>If there is a file <code>.mill-version</code> in the working directory, it’s content will be used as mill version. The file must have only a mill version as content, no additional content or comments are supported. Example</li>
+</ul>
+<p><code>
+ sh $ echo -n &quot;0.3.6&quot; &gt; .mill-version
+ sh $ mill --disable-ticker version
+ 0.3.6
+</code></p>
+<p>The values of the <code>DEFAULT_MILL_VERSION</code> variable inside the script will be used.</p><h3 id="use-cases" class="Styles-hoverBox">Use cases<a href="#use-cases" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3><h4 id="as-mill-executable" class="Styles-hoverBox">As mill executable<a href="#as-mill-executable" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h4>
+<p>Istead of installing mill, you can just place the script into you local <code>$HOME/bin</code> directory and rename it to <code>mill</code>.</p>
+<p>If you need a special mill version in a project directory, just place a <code>.mill-version</code> file with the best mill version. Example: setting mill 0.3.6 as best local mill version</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="">sh $ echo -n &quot;0.3.6&quot; &gt; .mill-version
+</code></pre><h4 id="as-a-wrapper-script-in-your-project" class="Styles-hoverBox">As a wrapper script in your project<a href="#as-a-wrapper-script-in-your-project" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h4>
+<p>To make the start for others easier or to always have the correct mill version in your CI environment, you can just place a copy of the script as <code>millw</code> in your project root directory.</p>
+<p>You should change the <code>DEFAULT_MILL_VERSION</code> variable in that script to the correct version you want to use and add the file under version control.</p><h2 id="osgi" class="Styles-hoverBox">OSGi<a href="#osgi" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Produce OSGi Bundles with mill.</p>
+<p>Project home: <a href="https://github.com/lefou/mill-osgi">https://github.com/lefou/mill-osgi</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, mill.scalalib._
+import $ivy.`de.tototec::de.tobiasroeser.mill.osgi:0.0.5`
+import de.tobiasroeser.mill.osgi._
+
+object project extends ScalaModule with OsgiBundleModule {
+
+ def bundleSymbolicName = &quot;com.example.project&quot;
+
+ def osgiHeaders = T{ super.osgiHeaders().copy(
+ `Export-Package` = Seq(&quot;com.example.api&quot;),
+ `Bundle-Activator` = Some(&quot;com.example.internal.Activator&quot;)
+ )}
+
+ // other settings ...
+
+}
+</code></pre><h2 id="publishm2" class="Styles-hoverBox">PublishM2<a href="#publishm2" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
+<p>Mill plugin to publish artifacts into a local Maven repository.</p>
+<p>Project home: <a href="https://github.com/lefou/mill-publishM2">https://github.com/lefou/mill-publishM2</a></p><h3 id="quickstart" class="Styles-hoverBox">Quickstart<a href="#quickstart" class=" Styles-hoverLink"><i class="fa fa-link" aria-hidden="true"></i></a></h3>
+<p>Just mix-in the <code>PublishM2Module</code> into your project. <code>PublishM2Module</code> already extends mill's built-in <code>PublishModule</code>.</p>
+<p>File: <code>build.sc</code></p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="scala">import mill._, scalalib._, publish._
+
+import $ivy.`de.tototec::de.tobiasroeser.mill.publishM2:0.0.1`
+import de.tobiasroeser.mill.publishM2._
+
+object project extends PublishModule with PublishM2Module {
+ // ...
+}
+</code></pre>
+<p>Publishing to default local Maven repository</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">&gt; mill project.publishM2Local
+[40/40] project.publishM2Local
+Publishing to /home/user/.m2/repository
+</code></pre>
+<p>Publishing to custom local Maven repository</p>
+<pre style="background-color: #f8f8f8"><code style="white-space:pre; background-color: #f8f8f8" class="bash">&gt; mill project.publishM2Local /tmp/m2repo
+[40/40] project.publishM2Local
+Publishing to /tmp/m2repo
+</code></pre><hr /><p><b>About the Author:</b><i> Haoyi is a software engineer, an early contributor to <a href="http://www.scala-js.org/">Scala.js</a>, and the author of many open-source Scala tools such as Mill, the <a href="http://lihaoyi.com/Ammonite">Ammonite REPL</a> and <a href="https://github.com/lihaoyi/fastparse">FastParse</a>. </i></p><p><i>If you've enjoy using Mill, or enjoyed using Haoyi's other open source libraries, please chip in (or get your Company to chip in!) via <a href="https://www.patreon.com/lihaoyi">Patreon</a> so he can continue his open-source work</i></p><hr /><div style="display: flex;flex-direction: row;justify-content: space-between;"><a href="contrib-modules.html"><i class="fa fa-arrow-left" aria-hidden="true"></i> Contrib Modules</a><div></div></div></div></body></html> \ No newline at end of file