Skip to content

Commit

Permalink
Documentation for query syntax (#2998)
Browse files Browse the repository at this point in the history
Tried to collect and document all ways to specify a target in Mill in a
single page.

Documentation in a foreign language is not my expertise, so please
comment, fix, or open more PRs. 

Pull request: #2998
  • Loading branch information
lefou authored Feb 5, 2024
1 parent 9884b03 commit dd2e54c
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* xref:Tasks.adoc[]
* xref:Modules.adoc[]
* xref:Cross_Builds.adoc[]
* xref:Target_Query_Syntax.adoc[]
* xref:Extending_Mill.adoc[]
* xref:The_Mill_Evaluation_Model.adoc[]
Expand Down
148 changes: 148 additions & 0 deletions docs/modules/ROOT/pages/Target_Query_Syntax.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
= Target Query Syntax

When interacting with Mill from the CLI, you often need to select targets or modules.
In most places, where Mill accepts a target, it really accepts a target selector query, which is the name of a target in its simplest form, but it can also contain wildcards, type pattern and other special syntax, making it a powerful tool to select specific targets.

== Selecting dedicated targets

When invoking Mill, the simplest way to run a target is to give it with a fully qualified names.

Examples:

----
> mill for.compile
> mill for.run hello world
> mill foo.testCached
----

.Understanding target paths and path segments
****
Each Mill module and target has a unique path.
Each part of the path is called _segment_.
Segments are separated with a dot (`.`).
They look like regular Scala class name qualifiers.
There are two kind of segments: _label segments_ and _cross segments_.
_Label segments_ are the components of a target path and have the same restriction as Scala identifiers.
The must start with a letter and may contain letters, numbers and a limited set of special characters `-` (dash), `_` (underscore).
They are used to denote Mill modules, tasks, but in the case of xref:Modules.adoc#external-modules[external modules] their Scala package names.
_Cross segments_ start with a label segment but contain additional square brackets (`[`, `]`]) and are used to denote cross module and their parameters.
NOTE: Segments can be surrounded by parentheses (`(`, `)`)).
When combined with <<type-filters,qualified type filter>> which contain dots (`.`), the parentheses need to be used, to avoid the dots to being interpreted as path separators.
****

[#select-multiple-targets]
== Selecting multiple targets

If you want to select more than one target, you have multiple options:

* <<enumerations,Use target enumerations>>
* <<wildcards,Use wildcard selections>>
* <<type-filters,Specify type filters on wildcard selections>>
* <<add-target-selector,Use `+` to use more than one target selector>>

You can also combine these techniques to properly select your targets

[#enumerations]
== Enumerations

Enumeration are denoted by curly braces (`{`, `}`).
Inside the curly braces you can place two or more selector paths, separated with a comma (`,`).

Examples:

* `{foo,bar}` simple enumerates two targets, `foo` and `bar`
* `foo.{compile,run}` expands to `foo.compile` and `foo.run`
* `{_,foo.bar}.baz` expands to `_.baz` and `foo.bar.baz`

[TIP]
====
Some Shells like `bash` support curly braces expansion.
Make sure to properly mask the selector path, e.g. by putting it in quotes.
[bash]
----
mill "foo.{compile.run}"
----
====

[#wildcards]
== Wildcard selections

There are two wildcards, you can use as path segment.

* `_` The single underscore acts as a placeholder for a single segment.

* `__` The double underscore acts as a placeholder for many segments.
In particular, it can represent an empty segment.

With wildcards, you can get explicit control over the position of a target in the build tree.

E.g. the filter `+_._._.jar+` will match all jar targets, that are on the third-level of the build tree.

[#type-filters]
== Type filters for wildcard selections

Type filters are always combined with wildcard.
They are used to limit the scope of the wildcard to only match path segments of the specified types.
For module paths this means, the represented module needs to be an instance of the specified type.

A type filter always starts with a wildcard (`_`, `__`) followed by a colon (`:`) and finally the _type qualifier_.

The type is matched by its name and optionally by its enclosing types and packages, separated by a `.` sign.
Since this is also used to separate target path segments, a type selector segment containing a `.` needs to be enclosed in parentheses.
A fully qualified type can be denoted with the _root_ package.

[sh]
----
> mill resolve __:TestModule.jar
> mill resolve "(__:scalalib.TestModule).jar"
> mill resolve "(__:mill.scalalib.TestModule).jar"
> mill resolve "(__:_root_.mill.scalalib.TestModule).jar"
----

If the type qualifier starts with a `^` or `!`, it's only matching types which are _not_ instances of the specified type.

[sh]
----
> mill resolve __:^TestModule.jar
----

You can also add more than one type filters to a wildcard.

[sh]
----
> mill resolve "__:JavaModule:^ScalaModule:^TestModule.jar"
----

NOTE: Type filter are currently only supported for module selections, but not for target selections.
That means, you can't filter based on the result type of a target.

[#add-target-selector]
== Start a new target selector with `+`

On the Mill CLI you can also start a complete new target selector with the `+` sign.

There is a subtile difference between the expansion of <<enumerations,enumerations>>, <<wildcards,wildcards>> and <<type-filters,wildcards with type filters>> in contrast to the <<add-target-selector,start of a new selector with `+`>>.

For all the former versions, Mill parses them into a complex but single target selector path and subsequent parameters are used for all resolved targets.

Whereas the `+` start a completely new selector path to which you can also provide a different parameter list. This is important when using xref:Tasks.adoc#commands[command targets] which can accept their own parameters. The `JavaModule.run` command is an example.

----
> mill foo.run hello # <1>
> mill {foo,bar}.run hello # <2>
> mill __:JavaModule:^TestModule.run # <3>
> mill foo.run hello + bar.run world # <4>
----

<1> Runs `foo.run` with the parameter `hello`
<2> Expands to `foo.run` and `bar.run` and runs both with the parameter `hello`.
<3> Selects the `run` command of all Java modules, but not test moudles, and runs them with the parameter `hello`.
<4> Runs `fun.run` with the parameter `hello` and `bar.run` with the parameter `world`.

1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/Tasks.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ different Task types:

include::example/tasks/1-task-graph.adoc[]

[#primitive-tasks]
== Primary Tasks

include::example/tasks/2-primary-tasks.adoc[]
Expand Down
1 change: 0 additions & 1 deletion example/basic/1-simple-scala/build.sc
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import mill._, scalalib._

object foo extends RootModule with ScalaModule {
Expand Down
1 change: 1 addition & 0 deletions example/tasks/2-primary-tasks/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ object bar extends Bar
*/

// [#commands]
// === Commands

def run(args: String*) = T.command {
Expand Down

0 comments on commit dd2e54c

Please sign in to comment.