Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ./mill without any arguments point you towards --help, flesh out --help into a cheat sheet #3556

Merged
merged 20 commits into from
Sep 16, 2024
2 changes: 1 addition & 1 deletion .config/mill-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.12.0-RC2
0.12.0-RC2
100 changes: 56 additions & 44 deletions docs/modules/ROOT/partials/Intro_to_Mill_Footer.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -56,55 +56,67 @@ Tasks that depend on each other can't be processed in parallel.

== Command-line usage

Mill is a command-line tool and supports various options.

Run `mill --help` for a complete list of options
Mill is a command-line tool and supports various options. Run `mill --help` for
a complete list of options and a cheat-sheet of how to work with tasks:

.Output of `mill --help`
[source,subs="verbatim,attributes"]
----
Mill Build Tool, version {mill-version}
usage: mill [options] [[target [target-options]] [+ [target ...]]]
-D --define <k=v> Define (or overwrite) a system property.
-b --bell Ring the bell once if the run completes successfully, twice if
it fails.
--bsp Enable BSP server mode.
--color <bool> Enable or disable colored output; by default colors are enabled
in both REPL and scripts mode if the console is interactive, and
disabled otherwise.
-d --debug Show debug output on STDOUT
--disable-callgraph-invalidation Disable the fine-grained callgraph-based target invalidation in
response to code changes, and instead fall back to the previous
coarse-grained implementation relying on the script `import
$file` graph
--disable-ticker Disable ticker log (e.g. short-lived prints of stages and
progress bars).
--enable-ticker <bool> Enable ticker log (e.g. short-lived prints of stages and
progress bars).
-h --home <path> (internal) The home directory of internally used Ammonite script
engine; where it looks for config and caches.
--help Print this help message and exit.
-i --interactive Run Mill in interactive mode, suitable for opening REPLs and
taking user input. This implies --no-server and no mill server
will be used. Must be the first argument.
--import <str> Additional ivy dependencies to load into mill, e.g. plugins.
-j --jobs <int> Allow processing N targets in parallel. Use 1 to disable
parallel and 0 to use as much threads as available processors.
-k --keep-going Continue build, even after build failures.
--meta-level <int> Experimental: Select a meta-build level to run the given
targets. Level 0 is the normal project, level 1 the first
meta-build, and so on. The last level is the built-in synthetic
meta-build which Mill uses to bootstrap the project.
--no-server Run Mill in single-process mode. In this mode, no Mill server
will be started or used. Must be the first argument.
-s --silent Make ivy logs during script import resolution go silent instead
of printing; though failures will still throw exception.
-v --version Show mill version information and exit.
-w --watch Watch and re-run your scripts when they change.
target <str>... The name or a pattern of the target(s) you want to build,
followed by any parameters you wish to pass to those targets. To
specify multiple target names or patterns, use the `+`
separator.
Usage: mill [options] task [task-options] [+ task ...]

task cheat sheet:
mill resolve _ # see all top-level tasks and modules
mill resolve __.compile # see all `compile` tasks in any module (recursively)

mill foo.bar.compile # compile the module `foo.bar`

mill foo.run --arg 1 # run the main method of the module `foo` and pass in `--arg 1`
mill -i foo.console # run the Scala console for the module `foo` (if it is a ScalaModule)

mill foo.__.test # run tests in modules nested within `foo` (recursively)
mill foo.test arg1 arg2 # run tests in the `foo` module passing in test arguments `arg1 arg2`
mill foo.test + bar.test # run tests in the `foo` module and `bar` module
mill '{foo,bar,qux}.test' # run tests in the `foo` module, `bar` module, and `qux` module

mill foo.assembly # generate an executable assembly of the module `foo`
mill show foo.assembly # print the output path of the assembly of module `foo`
mill inspect foo.assembly # show docs and metadata for the `assembly` task on module `foo`

mill clean foo.assembly # delete the output of `foo.assembly` to force re-evaluation
mill clean # delete the output of the entire build to force re-evaluation

mill path foo.run foo.sources # print the task chain showing how `foo.run` depends on `foo.sources`
mill visualize __.compile # show how the `compile` tasks in each module depend on one another

options:
-D --define <k=v> Define (or overwrite) a system property.
--allow-positional Allows command args to be passed positionally without `--arg` by default
-b --bell Ring the bell once if the run completes successfully, twice if it fails.
--bsp Enable BSP server mode.
--color <bool> Toggle colored output; by default enabled only if the console is interactive
-d --debug Show debug output on STDOUT
--disable-callgraph Disables fine-grained invalidation of tasks based on analyzing code changes.
If passed, you need to manually run `clean` yourself after build changes.
--help Print this help message and exit.
-i --interactive Run Mill in interactive mode, suitable for opening REPLs and taking user
input. This implies --no-server. Must be the first argument.
--import <str> Additional ivy dependencies to load into mill, e.g. plugins.
-j --jobs <str> The number of parallel threads. It can be an integer e.g. `5` meaning 5
threads, an expression e.g. `0.5C` meaning half as many threads as available
cores, or `C-2` meaning 2 threads less than the number of cores. `1` disables
parallelism and `0` (the default) uses 1 thread per core.
-k --keep-going Continue build, even after build failures.
--meta-level <int> Select a meta-level to run the given tasks. Level 0 is the main project in
`build.mill`, level 1 the first meta-build in `mill-build/build.mill`, etc.
--no-server Run without a background server. Must be the first argument.
-s --silent Make ivy logs during script import resolution go silent instead of printing
--ticker <bool> Enable ticker log (e.g. short-lived prints of stages and progress bars).
-v --version Show mill version information and exit.
-w --watch Watch and re-run the given tasks when when their inputs change.
task <str>... The name or a pattern of the tasks(s) you want to build.

Please see the documentation at https://mill-build.org for more details
----

All _options_ must be given before the first target.
2 changes: 1 addition & 1 deletion example/depth/tasks/2-primary-tasks/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ Expected Signature: run
args <str>...
...

> ./mill --allow-positional-command-args run foo.Foo hello world # this succeeds due to --allow-positional-command-args
> ./mill --allow-positional run foo.Foo hello world # this succeeds due to --allow-positional
Foo.value: 31337
args: hello world
foo.txt resource: My Example Text
Expand Down
10 changes: 6 additions & 4 deletions integration/feature/scoverage/src/ScoverageTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import utest._

object ScoverageTests extends UtestIntegrationTestSuite {
val tests: Tests = Tests {
test("test") - integrationTest { tester =>
import tester._
assert(eval("__.compile").isSuccess)
assert(eval("core[2.13.11].scoverage.xmlReport").isSuccess)
test("test") - retry(3) {
integrationTest { tester =>
import tester._
assert(eval("__.compile").isSuccess)
assert(eval("core[2.13.11].scoverage.xmlReport").isSuccess)
}
}
}
}
2 changes: 1 addition & 1 deletion main/eval/src/mill/eval/EvaluatorImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private[mill] case class EvaluatorImpl(
threadCount: Option[Int] = Some(1),
scriptImportGraph: Map[os.Path, (Int, Seq[os.Path])] = Map.empty,
methodCodeHashSignatures: Map[String, Int],
override val disableCallgraphInvalidation: Boolean,
override val disableCallgraph: Boolean,
override val allowPositionalCommandArgs: Boolean,
val systemExit: Int => Nothing
) extends Evaluator with EvaluatorCore {
Expand Down
105 changes: 53 additions & 52 deletions main/eval/src/mill/eval/GroupEvaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private[mill] trait GroupEvaluator {
def threadCount: Option[Int]
def scriptImportGraph: Map[os.Path, (Int, Seq[os.Path])]
def methodCodeHashSignatures: Map[String, Int]
def disableCallgraphInvalidation: Boolean
def disableCallgraph: Boolean
def systemExit: Int => Nothing

lazy val constructorHashSignatures: Map[String, Seq[(String, Int)]] = methodCodeHashSignatures
Expand Down Expand Up @@ -64,59 +64,60 @@ private[mill] trait GroupEvaluator {

val sideHashes = MurmurHash3.orderedHash(group.iterator.map(_.sideHash))

val scriptsHash = group
.iterator
.collect {
case namedTask: NamedTask[_] =>
val encodedTaskName = encode(namedTask.ctx.segment.pathSegments.head)
val methodOpt = for {
parentCls <- classToTransitiveClasses(namedTask.ctx.enclosingCls).iterator
m <- allTransitiveClassMethods(parentCls).get(encodedTaskName)
} yield m

val methodClass = methodOpt
.nextOption()
.getOrElse(throw new MillException(
s"Could not detect the parent class of target ${namedTask}. " +
s"Please report this at ${BuildInfo.millReportNewIssueUrl} . " +
s"As a workaround, you can run Mill with `--disable-callgraph-invalidation` option."
))
.getDeclaringClass.getName

val name = namedTask.ctx.segment.pathSegments.last
val expectedName = methodClass + "#" + name + "()mill.define.Target"

// We not only need to look up the code hash of the Target method being called,
// but also the code hash of the constructors required to instantiate the Module
// that the Target is being called on. This can be done by walking up the nested
// modules and looking at their constructors (they're `object`s and should each
// have only one)
val allEnclosingModules = Vector.unfold(namedTask.ctx) {
case null => None
case ctx =>
ctx.enclosingModule match {
case null => None
case m: mill.define.Module => Some((m, m.millOuterCtx))
case unknown =>
throw new MillException(s"Unknown ctx of target ${namedTask}: $unknown")
}
}
val scriptsHash =
if (disableCallgraph) 0
else group
.iterator
.collect {
case namedTask: NamedTask[_] =>
val encodedTaskName = encode(namedTask.ctx.segment.pathSegments.head)
val methodOpt = for {
parentCls <- classToTransitiveClasses(namedTask.ctx.enclosingCls).iterator
m <- allTransitiveClassMethods(parentCls).get(encodedTaskName)
} yield m

val methodClass = methodOpt
.nextOption()
.getOrElse(throw new MillException(
s"Could not detect the parent class of target ${namedTask}. " +
s"Please report this at ${BuildInfo.millReportNewIssueUrl} . "
))
.getDeclaringClass.getName

val name = namedTask.ctx.segment.pathSegments.last
val expectedName = methodClass + "#" + name + "()mill.define.Target"

// We not only need to look up the code hash of the Target method being called,
// but also the code hash of the constructors required to instantiate the Module
// that the Target is being called on. This can be done by walking up the nested
// modules and looking at their constructors (they're `object`s and should each
// have only one)
val allEnclosingModules = Vector.unfold(namedTask.ctx) {
case null => None
case ctx =>
ctx.enclosingModule match {
case null => None
case m: mill.define.Module => Some((m, m.millOuterCtx))
case unknown =>
throw new MillException(s"Unknown ctx of target ${namedTask}: $unknown")
}
}

val constructorHashes = allEnclosingModules
.map(m =>
constructorHashSignatures.get(m.getClass.getName) match {
case Some(Seq((singleMethod, hash))) => hash
case Some(multiple) => throw new MillException(
s"Multiple constructors found for module $m: ${multiple.mkString(",")}"
)
case None => 0
}
)
val constructorHashes = allEnclosingModules
.map(m =>
constructorHashSignatures.get(m.getClass.getName) match {
case Some(Seq((singleMethod, hash))) => hash
case Some(multiple) => throw new MillException(
s"Multiple constructors found for module $m: ${multiple.mkString(",")}"
)
case None => 0
}
)

methodCodeHashSignatures.get(expectedName) ++ constructorHashes
}
.flatten
.sum
methodCodeHashSignatures.get(expectedName) ++ constructorHashes
}
.flatten
.sum

val inputsHash = externalInputsHash + sideHashes + classLoaderSigHash + scriptsHash

Expand Down
4 changes: 2 additions & 2 deletions runner/src/mill/runner/MillBuildBootstrap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class MillBuildBootstrap(
targetsAndParams: Seq[String],
prevRunnerState: RunnerState,
logger: ColorLogger,
disableCallgraphInvalidation: Boolean,
disableCallgraph: Boolean,
needBuildSc: Boolean,
requestedMetaLevel: Option[Int],
allowPositionalCommandArgs: Boolean,
Expand Down Expand Up @@ -351,7 +351,7 @@ class MillBuildBootstrap(
failFast = !keepGoing,
threadCount = threadCount,
methodCodeHashSignatures = methodCodeHashSignatures,
disableCallgraphInvalidation = disableCallgraphInvalidation,
disableCallgraph = disableCallgraph,
allowPositionalCommandArgs = allowPositionalCommandArgs,
systemExit = systemExit
)
Expand Down
Loading
Loading