Skip to content

Commit

Permalink
Adjust codegen to allow custom mainargs.TokensReaders and exercise …
Browse files Browse the repository at this point in the history
…it via example tests for `Bundle Libraries` docs (#3504)

* Includes a `mainargs.TokensReader[os.Path]` by default for
convenience, and added example tests for 4 of the listed bundled
libraries
* Removed the type parameter from `Discover[T]`, since it was not
necessary and only ever caused type inference problems
* Moved the `lazy val millDiscover = Discover[T]` call from the
`MillMiscInfo` object to the main body of the class containing user
code, so it can see anything the user writes in `build.mill`, including
`TokensReader` instances. The old reasoning for having it outside (that
we want it to propagate implicitly to be picked up by nested
`RootModule`s) no longer applies with the codegen-time `RootModule`
unpacking

Fixes #2029
Fixes #2857
  • Loading branch information
lihaoyi committed Sep 10, 2024
1 parent 649eb5f commit 40b1920
Show file tree
Hide file tree
Showing 51 changed files with 573 additions and 169 deletions.
2 changes: 1 addition & 1 deletion bsp/src/mill/bsp/BSP.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import mill.scalalib.CoursierModule

object BSP extends ExternalModule with CoursierModule {

lazy val millDiscover: Discover[this.type] = Discover[this.type]
lazy val millDiscover: Discover = Discover[this.type]

private def bspWorkerLibs: T[Agg[PathRef]] = T {
millProjectModule("mill-bsp-worker", repositoriesTask())
Expand Down
4 changes: 2 additions & 2 deletions bsp/worker/src/mill/bsp/worker/MillBuildServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private class MillBuildServer(
) extends ExternalModule
with BuildServer {

lazy val millDiscover: Discover[this.type] = Discover[this.type]
lazy val millDiscover: Discover = Discover[this.type]

private[worker] var cancellator: Boolean => Unit = shutdownBefore => ()
private[worker] var onSessionEnd: Option[BspServerResult => Unit] = None
Expand Down Expand Up @@ -567,7 +567,7 @@ private class MillBuildServer(
case ((msg, cleaned), targetId) =>
val (module, ev) = state.bspModulesById(targetId)
val mainModule = new MainModule {
override implicit def millDiscover: Discover[_] = Discover[this.type]
override implicit def millDiscover: Discover = Discover[this.type]
}
val compileTargetName = (module.millModuleSegments ++ Label("compile")).render
debug(s"about to clean: ${compileTargetName}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,5 @@ object ArtifactoryPublishModule extends ExternalModule {
}
}

lazy val millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
lazy val millDiscover: mill.define.Discover = mill.define.Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,5 @@ object BintrayPublishModule extends ExternalModule {
}
}

lazy val millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
lazy val millDiscover: mill.define.Discover = mill.define.Discover[this.type]
}
2 changes: 1 addition & 1 deletion contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -442,5 +442,5 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule {
}
}

lazy val millDiscover: Discover[this.type] = Discover[this.type]
lazy val millDiscover: Discover = Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ object CodeartifactPublishModule extends ExternalModule {
)
}

lazy val millDiscover: mill.define.Discover[this.type] =
lazy val millDiscover: mill.define.Discover =
mill.define.Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,5 @@ object GitlabPublishModule extends ExternalModule {
)
}

lazy val millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
lazy val millDiscover: mill.define.Discover = mill.define.Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ trait RouteCompilerWorkerModule extends Module {
private[playlib] object RouteCompilerWorkerModule
extends ExternalModule
with RouteCompilerWorkerModule {
lazy val millDiscover: Discover[this.type] = Discover[this.type]
lazy val millDiscover: Discover = Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,5 @@ trait ScalaPBWorkerApi {

object ScalaPBWorkerApi extends ExternalModule {
def scalaPBWorker: Worker[ScalaPBWorker] = T.worker { new ScalaPBWorker() }
lazy val millDiscover: Discover[this.type] = Discover[this.type]
lazy val millDiscover: Discover = Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ object ScoverageReportWorker extends ExternalModule {

def scoverageReportWorker: Worker[ScoverageReportWorker] =
T.worker { new ScoverageReportWorker() }
lazy val millDiscover: Discover[this.type] = Discover[this.type]
lazy val millDiscover: Discover = Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,5 @@ object SonatypeCentralPublishModule extends ExternalModule {
Result.Success(SonatypeCredentials(username, password))
}

lazy val millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
lazy val millDiscover: mill.define.Discover = mill.define.Discover[this.type]
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,5 @@ object VersionFileModule extends define.ExternalModule {
} yield proc.call()
}

lazy val millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
lazy val millDiscover: mill.define.Discover = mill.define.Discover[this.type]
}
28 changes: 7 additions & 21 deletions docs/modules/ROOT/pages/Bundled_Libraries.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,33 @@ Mill comes bundled with a set of external Open Source libraries and projects.

== OS-lib

OS-Lib is a simple, flexible, high-performance Scala interface to common OS
filesystem and subprocess APIs.

Mill uses OS-Lib for all of its file system operations.

Project page:: https://github.com/com-lihaoyi/os-lib
ScalaDoc:: https://javadoc.io/doc/com.lihaoyi/os-lib_2.13/latest/index.html

include::example/external/libraries/1-oslib.adoc[]

== uPickle

uPickle: a simple Scala JSON and Binary (MessagePack) serialization library

Mill uses uPickle to cache target output to disk as JSON, and to output JSON
for third-party tools to consume.

Project page:: https://github.com/com-lihaoyi/upickle
ScalaDoc:: https://javadoc.io/doc/com.lihaoyi/upickle_2.13/latest/index.html

== Requests-Scala

Requests-Scala is a Scala port of the popular Python Requests HTTP client.
Requests-Scala aims to provide the same API and user-experience as the
original Requests: flexible, intuitive, and straightforward to use.
include::example/external/libraries/2-upickle.adoc[]

Mill bundles Requests for you to use to make HTTP requests.
== Requests-Scala

Project page:: https://github.com/com-lihaoyi/requests-scala
ScalaDoc:: https://javadoc.io/doc/com.lihaoyi/requests_2.13/latest/index.html

== MainArgs
include::example/external/libraries/3-requests.adoc[]

MainArgs is a small, dependency-free library for command line argument parsing
in Scala.
== MainArgs

Mill uses MainArgs to handle argument parsing for ``T.command``s that are run
from the command line.

Project page:: https://github.com/com-lihaoyi/mainargs
Scaladoc:: https://javadoc.io/doc/com.lihaoyi/mainargs_2.13/latest/index.html

include::example/external/libraries/4-mainargs.adoc[]

== Coursier

Coursier is the Scala application and artifact manager. Mill uses Coursier for
Expand Down
29 changes: 0 additions & 29 deletions docs/modules/ROOT/pages/Tasks.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,35 +51,6 @@ include::example/depth/tasks/5-persistent-targets.adoc[]
include::example/depth/tasks/6-workers.adoc[]


=== Evaluator Commands (experimental)

_Evaluator Command are experimental and suspected to change.
See {mill-github-url}/issues/502[issue #502] for details._

You can define a command that takes in the current `Evaluator` as an argument,
which you can use to inspect the entire build, or run arbitrary tasks.
For example, here is the `mill.scalalib.GenIdea/idea` command which uses this
to traverse the module-tree and generate an Intellij project config for your
build.

[source,scala]
----
def idea(ev: Evaluator) = T.command {
mill.scalalib.GenIdea(
implicitly,
ev.rootModule,
ev.discover
)
}
----

Many built-in tools are implemented as custom evaluator commands:
xref:Scala_Builtin_Commands.adoc#_inspect[inspect],
xref:Scala_Builtin_Commands.adoc#_resolve[resolve],
xref:Scala_Builtin_Commands.adoc#_show[show].
If you want a way to run Mill commands and programmatically manipulate the
tasks and outputs, you do so with your own evaluator command.

== Using ScalaModule.run as a task

include::example/depth/tasks/11-module-run-task.adoc[]
43 changes: 43 additions & 0 deletions example/external/libraries/1-oslib/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Mill uses OS-Lib for all of its file system and subprocess operations.
//
// === Sandbox Working Directories
//
// One thing to note about Mill's usage of OS-Lib is that Mill sets the `os.pwd`
// and for filesystem operations and subprocesses to each task's `.dest` folder,
// as part of its xref:Mill_Sandboxing.adoc[] efforts to prevent accidental
// interference between tasks:

import mill._

def task1 = T{
os.write(os.pwd / "file.txt", "hello")
PathRef(os.pwd / "file.txt")
}

def task2 = T{
os.call(("bash", "-c", "echo 'world' >> file.txt"))
PathRef(os.pwd / "file.txt")
}

def command = T{
println(task1().path)
println(os.read(task1().path))
println(task2().path)
println(os.read(task2().path))
}

// Thus although both `task1` and `task2` above write to `os.pwd / "file.txt"` -
// one via `os.write` and one via a Bash subprocess - each task gets its own
// working directory that prevents the files from colliding on disk. Thus the final
// `command` can depend on both tasks and read each task's `file.txt` separately
// without conflict

/** Usage

> ./mill command # mac/linux
.../out/task1.dest/file.txt
hello
.../out/task2.dest/file.txt
world

*/
102 changes: 102 additions & 0 deletions example/external/libraries/2-upickle/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Mill uses uPickle to cache target output to disk as JSON, and to output JSON
// for third-party tools to consume. The output of every Mill target must be JSON
// serializable via uPickle.
//
// The uPickle serialized return of every Mill task is used for multiple purposes:
//
// - As the format for caching things on disk
//
// - The output format for `show`, which can be used for manual inspection piped
// to external tools
//
// - Decided whether downstream results can be read from the cache or whether they
// need to be recomputed
//
// === Primitives and Collections
//
// Most Scala primitive types (``String``s, ``Int``s, ``Boolean``s, etc.) and
// collections types (``Seq``s, ``List``s, ``Tuple``s, etc.) are serializable by default.

import mill._

def taskInt = T{ 123 }
def taskBoolean = T{ true }
def taskString = T{ "hello " + taskInt() + " world " + taskBoolean() }


/** Usage

> ./mill show taskInt
123

> ./mill show taskBoolean
true

> ./mill show taskString
"hello 123 world true"

> ./mill show taskTuple
[
123,
true,
"hello 123 world true"
]
*/

def taskTuple = T{ (taskInt(), taskBoolean(), taskString())}
def taskSeq = T{ Seq(taskInt(), taskInt() * 2, taskInt() * 3)}
def taskMap = T{ Map("int" -> taskInt().toString, "boolean" -> taskBoolean().toString) }


/** Usage
> ./mill show taskSeq
[
123,
246,
369
]

> ./mill show taskMap
{
"int": "123",
"boolean": "true"
}

*/

// === Paths and PathRef
//
// ``os.Path``s from OS-Lib are also serializable as strings.

def taskPath = T{
os.write(os.pwd / "file.txt", "hello")
os.pwd / "file.txt"
}

/** Usage

> ./mill show taskPath
".../out/taskPath.dest/file.txt"

*/

// Note that returning an `os.Path` from a task will only invalidate downstream
// tasks on changes to the path itself (e.g. from returning `file.txt` to `file2.txt`),
// and not to changes to the contents of any file or folder at that path. If you want
// to invalidate downstream tasks depending on the contents of a file or folder, you
// should return a `PathRef`:

def taskPathRef = T{
os.write(os.pwd / "file.txt", "hello")
PathRef(os.pwd / "file.txt")
}

/** Usage

> ./mill show taskPathRef
"ref.../out/taskPathRef.dest/file.txt"

*/

// The serialized `PathRef` contains a hexadecimal hash signature of the file or
// folder referenced on disk, computed from its contents.
Loading

0 comments on commit 40b1920

Please sign in to comment.