diff options
Diffstat (limited to 'docs/pages/2 - Configuring Mill.md')
-rw-r--r-- | docs/pages/2 - Configuring Mill.md | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/docs/pages/2 - Configuring Mill.md b/docs/pages/2 - Configuring Mill.md new file mode 100644 index 00000000..8fee9354 --- /dev/null +++ b/docs/pages/2 - Configuring Mill.md @@ -0,0 +1,277 @@ +You can configure your Mill build in a number of ways: + +## Compilation & Execution Flags + +```scala +import mill._ +import mill.scalalib._ +object foo extends ScalaModule { + def scalaVersion = "2.12.4" + + def scalacOptions = Seq("-Ydelambdafy:inline") + + def forkArgs = Seq("-Xmx4g") + + def forkEnv = Map("HELLO_MY_ENV_VAR" -> "WORLD") +} +``` + +You can pass flags to the Scala compiler via `scalacOptions`. By default, +`foo.run` runs the compiled code in a subprocess, and you can pass in JVM flags +via `forkArgs` or environment-variables via `forkEnv`. + +You can also run your code via + +```bash +mill foo.runLocal +``` + +Which runs it in-process within an isolated classloader. This may be faster +since you avoid the JVM startup, but does not support `forkArgs` or `forkEnv`. + +## Adding Ivy Dependencies + +```scala +import mill._ +import mill.scalalib._ +object foo extends ScalaModule { + def scalaVersion = "2.12.4" + def ivyDeps = Agg( + ivy"com.lihaoyi::upickle:0.5.1", + ivy"com.lihaoyi::pprint:0.5.2", + ivy"com.lihaoyi::fansi:0.2.4" + ) +} +``` + +You can define the `ivyDeps` field to add ivy dependencies to your module. The +`ivy"com.lihaoyi::upickle:0.5.1"` syntax (with `::`) represents Scala +dependencies; for Java dependencies you would use a single `:` e.g. +`ivy"com.lihaoyi:upickle:0.5.1"`. + +By default these are resolved from maven central, but you can add your own +resolvers by overriding the `repositories` definition in the module: + +```scala +def repositories = super.repositories ++ Seq( + MavenRepository("https://oss.sonatype.org/content/repositories/releases") +) +``` + +## Adding a Test Suite + +```scala +import mill._ +import mill.scalalib._ +object foo extends ScalaModule { + def scalaVersion = "2.12.4" + + object test extends Tests{ + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.6.0") + def testFramework = "mill.UTestFramework" + } +} +``` + +You can define a test suite by creating a nested module extending `Tests`, and +specifying the ivy coordinates and name of your test framework. This expects the +tests to be laid out as follows: + +``` +build.sc +foo/ + src/ + Main.scala + resources/ + ... + test/ + src/ + MainTest.scala + resources/ + ... +out/ + foo/ + ... + test/ + ... +``` + +The above example can be run via + +```bash +mill foo.test +``` + +By default, tests are run in a subprocess, and `forkArg` and `forkEnv` can be +overriden to pass JVM flags & environment variables. You can also use + +```bash +mill foo.test.testLocal +``` + +To run tests in-process in an isolated classloader. + +You can define multiple test suites if you want, e.g.: + +```scala +import mill._ +import mill.scalalib._ +object foo extends ScalaModule { + def scalaVersion = "2.12.4" + + object test extends Tests{ + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.6.0") + def testFramework = "mill.UTestFramework" + } + object integration extends Tests{ + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.6.0") + def testFramework = "mill.UTestFramework" + } +} +``` + +Each of which will expect their sources to be in their respective `foo/test` and +`foo/integration` folder. + +`Tests` modules are `ScalaModule`s like any other, and all the same +configuration options apply. + + +## Scala Compiler Plugins + +```scala +import mill._ +import mill.scalalib._ +object foo extends ScalaModule { + def scalaVersion = "2.12.4" + + def compileIvyDeps = Agg(ivy"com.lihaoyi::acyclic:0.1.7") + def scalacOptions = Seq("-P:acyclic:force") + def scalacPluginIvyDeps = Agg(ivy"com.lihaoyi::acyclic:0.1.7") +} +``` + +You can use Scala compiler plugins by setting `scalacPluginIvyDeps`. The above +example also adds the plugin to `compileIvyDeps`, since that plugin's artifact +is needed on the compilation classpath (though not at runtime). + +## Common Configuration + +```scala +import mill._ +import mill.scalalib._ +trait CommonModule extends ScalaModule{ + def scalaVersion = "2.12.4" +} + +object foo extends CommonModule +object bar extends CommonModule { + def moduleDeps = Seq(foo) +} +``` + +You can extract out configuration common to multiple modules into a `trait` that +those modules extend. This is useful for providing convenience & 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 +`trait`. + +## Custom Tasks + +```scala +import mill._ +import mill.scalalib._ +object foo extends ScalaModule { + def scalaVersion = "2.12.4" +} + +def lineCount = T{ + import ammonite.ops._ + foo.sources().flatMap(ref => ls.rec(ref.path)).flatMap(read.lines).size +} + +def printLineCount() = T.command{ + println(lineCount()) +} +``` + +You can define new cached Targets using the `T{...}` syntax, depending on +existing Targets e.g. `foo.sources` via the `foo.sources()` syntax to extract +their current value, as shown in `lineCount` above. The return-type of a Target +has to be JSON-serializable (using +[uPickle](https://github.com/lihaoyi/upickle)) and the Target is cached when +first run until it's inputs change (in this case, if someone edits the +`foo.sources` files which live in `foo/src`. Cached Targets cannot take +parameters. + +You can print the value of your custom target using `show`, e.g. + +```bash +mill run show lineCount +``` + +You can define new un-cached Commands using the `T.command{...}` 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 `(): Unit` if you want +to return nothing. + +## Custom Modules + +```scala +import mill._ +import mill.scalalib._ +object qux extends Module{ + object foo extends ScalaModule { + def scalaVersion = "2.12.4" + } + object bar extends ScalaModule { + def moduleDeps = Seq(foo) + def scalaVersion = "2.12.4" + } +} +``` + +Not every Module needs to be a `ScalaModule`; sometimes you just want to group +things together for neatness. In the above example, you can run `foo` and `bar` +namespaced inside `qux`: + +```bash +mill qux.foo.compile +mill qux.bar.run +``` + +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,: + +```scala +trait MySpecialModule extends Module{ + ... +} +object foo extends MySpecialModule +object bar extends MySpecialModule +``` + +## Overriding Tasks + +```scala +import mill._ +import mill.scalalib._ + +object foo extends ScalaModule { + def scalaVersion = "2.12.4" + def compile = T{ + println("Compiling...") + super.compile() + } + def run(args: String*) = T.command{ + println("Running... + args.mkString(" ")) + super.run(args:_*) + } +} +``` + +You can re-define targets and commands to override them, and use `super` if you +want to refer to the originally defined task. The above example shows how to +override `compile` and `run` to add additional logging messages. + +In Mill builds the `override` keyword is optional. |