Skip to content

Commit

Permalink
Doc Review Java Library Dependencies to Java Web Project Examples (
Browse files Browse the repository at this point in the history
  • Loading branch information
lihaoyi authored Jan 28, 2025
1 parent fca7af5 commit 76b8f64
Show file tree
Hide file tree
Showing 26 changed files with 175 additions and 120 deletions.
67 changes: 43 additions & 24 deletions docs/modules/ROOT/pages/cli/installation-ide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ globally.
[#_bootstrap_scripts]
== Bootstrap Scripts
Although the Mill example projects come with their own `./mill` and `./mill.bat` bootstrap script,
you can also download it manually:
The Mill example projects in this documentation come with `./mill` and `./mill.bat`
bootstrap script, included. You can also download the boostrap script manually:
[source,bash,subs="verbatim,attributes"]
----
Expand Down Expand Up @@ -58,7 +58,7 @@ pick one most similar to what you are doing so you can hit the ground running wo

The default Mill executable configured above requires a JVM (11 or above) installed globally in
order to run, and imposes some Java startup overhead (100-200ms) when running Mill from the
command line.You can also use Mill's native executables by appending a `-native` suffix to the
command line. You can also use Mill's native executables by appending a `-native` suffix to the
Mill version:

[source,bash,subs="verbatim,attributes"]
Expand All @@ -67,27 +67,41 @@ echo {mill-last-tag}-native > .mill-version
----

Using the `-native` suffix should provide a faster CLI experience than using Mill's default
JVM launcher. Mill native executables are supported on the following OS/CPU combinations:
JVM launcher, and makes it easier to install Mill in environments without a JVM pre-installed.

- `windows-amd64` (Intel Windows)
- `linux-amd64` (Intel Linux)
- `mac-aarch64` (M1-M4 Mac)

If you are on a combination not supported by Mill's native executables, use the default
Mill native executables are supported on the following OS/CPU combinations:

|===
| | Windows | Mac | Linux
| Intel | Y | Y | Y
| ARM | | Y | Y
|===

Notably, Mill native executables _do not_ support Windows-ARM, due to limitations in the
upstream Graal Native Image tooling (see https://github.com/oracle/graal/issues/9215[oracle/graal#9215]).
If you are on a platform not supported by Mill's native executables, use the default
JVM launcher instead.

=== Customizing Mill's JVM

To use Mill in environments without a JVM installed, the native launcher can download its
own JVM as necessary. You need to specify the version you want via a `.mill-jvm-version`
file such as:
Mill allows you to specify the exact JVM version you want to use to run the build tool
via a `.mill-jvm-version` file such as:

```bash
echo temurin:17.0.6 > .mill-jvm-version
```

`.mill-jvm-version` can also be used with Mill's default JVM launcher, if you want
your Mill process to use a different JVM than what you have installed globally.
This has two benefits

* `.mill-jvm-version` can also be used with Mill's default JVM launcher if you want
your Mill process to use a different JVM than what you have installed globally. This
can help ensure your project uses a consistent JVM version and behaves identically regardless
of what the developer may have installed on their laptop or dev environment

* `.mill-jvm-version` can be used together with <<Mill Native Executable>>s to build your
project without needing a JVM pre-installed at all. This simplifies project setup and
onboarding of new developers.


== IDE Support
Expand All @@ -97,12 +111,7 @@ your Mill process to use a different JVM than what you have installed globally.
Mill supports IntelliJ and VSCode and in general any client of the standard
https://build-server-protocol.github.io/[Build Server Protocol (BSP)].

To prepare your project for IDEs, and in general any BSP client, you can run this command to generate the BSP configuration files:

[source,bash]
----
./mill mill.bsp.BSP/install
----

Your IDEs may already auto-detect the Mill project and run this command on behalf of you, when opening/importing the project.

Expand All @@ -111,7 +120,7 @@ Your IDEs may already auto-detect the Mill project and run this command on behal
To use Mill with IntelliJ, first ensure you have the free
https://plugins.jetbrains.com/plugin/1347-scala[IntelliJ Scala Plugin]
installed. This is necessary as Mill build files are written in Scala,
even if you are using it to build a Java or Kotlin project.
even if you are using it to build a Java or Kotlin or Python project.

Once you have the plugin installed, you can use IntelliJ to open any project
containing a Mill `build.mill` file, and IntelliJ will automatically load the
Expand Down Expand Up @@ -139,6 +148,14 @@ those updates by opening the "BSP" tab and clicking the "Refresh" button

image::basic/IntellijRefresh.png[]

To prepare your project for IDEs, and in general any BSP client, you can also
run this command to generate the BSP configuration files:

[source,bash]
----
./mill mill.bsp.BSP/install
----

==== IntelliJ IDEA XML Support

Apart from using the Build Server Protocol, you can also generate IDEA project
Expand Down Expand Up @@ -235,7 +252,7 @@ MILL_VERSION=0.5.0-3-4faefb ./mill __.compile
to override the Mill version manually. This takes precedence over the version
specified in `./mill`, `.config/mill-version` or `.mill-version`

== Working without access to Maven Central
== Using Mill without access to Maven Central

Under some circumstances (e.g. corporate firewalls), you may not have access maven central.
The typical symptom will be error messages which look like this;
Expand All @@ -251,19 +268,21 @@ Resolution failed for 1 modules:
----
It is expected that basic commands (e.g. clean) will not work, as Mill saying it is
unable to resolve it's own, fundamental, dependencies. Under such circumstances, you
unable to resolve it's own, fundamental, dependencies from the default Maven Central
JVM package repository. Under such circumstances, you
will normally have access to some proxy, or other corporate repository which resolves
maven artifacts. The strategy is simply to tell mill to use that instead.
The idea is to set an environment variable COURSIER_REPOSITORIES (see coursier docs).
To resolve this, you can set an environment variable COURSIER_REPOSITORIES (see coursier docs)
to point at your own server that mirrors the Maven Central artifacts.
The below command should pass the environment variable to the `mill` command.
----
COURSIER_REPOSITORIES=https://packages.corp.com/artifactory/maven/ mill resolve _
COURSIER_REPOSITORIES=https://packages.corp.com/artifactory/maven/ mill resolve _
----
If you are using bootstrap script, a more permanent solution could be to set the environment variable
at the top of the bootstrap script, or as a user environment variable etc.
at the top of the bootstrap script, or as a user environment variable.
Expand Down
26 changes: 15 additions & 11 deletions docs/modules/ROOT/pages/comparisons/why-mill.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,12 @@ the Gradle build in an IDE, the IDE can only explore the configuration logic (th
`getCompilerArgs` method above) and is unable to explore the actual build logic (how
`getCompilerArgs` _actually gets used in Gradle_)

In comparison, Mill's `.mill` files are all statically typed, and as a result IntelliJ is easily able to
pull up the documentation for `def javacOptions`, even though it doesn't have any special support
for Mill built into the IDE:
In comparison, not only are Mill's `.mill` files statically typed, allowing IDEs like IntelliJ
to pull up the documentation for `def javacOptions`:

image::comparisons/IntellijMockitoMillJavacOptionsDocs.png[]

Apart from static typing, the way Mill builds are structured also helps the IDE: Mill
The way Mill builds are structured also helps the IDE: Mill
code _actually performs your build_, rather than configuring some opaque build engine.
While that sounds academic, one concrete consequence is that IntelliJ is able to take
your `def javacOptions` override and
Expand Down Expand Up @@ -364,7 +363,7 @@ Line Count: 18
Next, we'll look at a more realistic example,
which includes usage of third-party libraries in the build.

### Using Libraries from Maven Central in Tasks
### Using Third-Party JVM Libraries in Tasks

Earlier on we discussed possibly pre-rendering HTML pages in the build so they can be
served at runtime. The use case for this are obvious: if a page never changes, rendering
Expand All @@ -386,9 +385,14 @@ import $ivy.`org.thymeleaf:thymeleaf:3.1.1.RELEASE`
import org.thymeleaf.TemplateEngine
import org.thymeleaf.context.Context
object foo extends JavaModule {
/** Total number of lines in module source files */
def lineCount = Task {
allSourceFiles().map(f => os.read.lines(f.path).size).sum
}

def htmlSnippet = Task {
val context = new Context()
context.setVariable("heading", "hello")
context.setVariable("heading", "Line Count is: " + lineCount())
new TemplateEngine().process(
"<h1 th:text=\"${heading}\"></h1>",
context
Expand All @@ -411,14 +415,14 @@ is inspectable from the Mill command line via `show`, and we wire it up into

```bash
> mill show foo.htmlSnippet
"<h1>hello</h1>"
"<h1>Line count is: 17</h1>"

> mill foo.compile
compiling 1 Java source...
...

> mill foo.run
generated snippet.txt resource: <h1>hello</h1>
generated snippet.txt resource: <h1>Line count is: 17</h1>
```

Rendering HTML using the Thymeleaf templating engine is not rocket science, but what is
Expand All @@ -434,9 +438,9 @@ interesting here is what we did _not_ need to do:
implement the functionality we need.


Instead, we could simply import Thymeleaf directly from Maven Central and use it just
like we would use it in any Java application, with IDE support, typechecking,
and automatic parallelism and caching.
Instead, we could simply import Thymeleaf as a Java library directly from Maven Central
and use it just like we would use it in any Java application, with IDE support,
typechecking, and automatic parallelism and caching.

'''

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/pythonlib/dependencies.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ include::partial$gtag-config.adoc[]


This page goes into more detail about configuring third party dependencies
for `PythonModule`s.
for ``PythonModule``s.

== Adding Dependencies

Expand Down
23 changes: 23 additions & 0 deletions example/cli/builtins/1-builtin-commands/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,26 @@ kotlinlib/web/1-hello-ktor
// project isn't going to be everything that you need, at least it'll get most of the
// tedious boilerplate set up, so you can hit the group running working on the things
// that are unique to your particular project..
//
// `init` can also be used to initialize a Mill build configuration based on
// an existing Maven or Gradle build. See the linked page for more details:
//
// * xref:migrating/maven.adoc[]
// * xref:migrating/gradle.adoc[]
//
// == selective.*
//
// Mill comes with builtin `selective.*` commands to work with Selective Test Execution.
// See the linked page for more details:
//
// * xref:large/selective-execution.adoc[]
//
// == shutdown
//
// `./mill shutdown` is used to shut down the background daemon that Mill uses to keep
// the build code performant. Without calling `shutdown`, the background daemon will
// automatically shut itself down after 30 minutes of inactivity.

// == version
//
// `./mill version` prints the current Mill version
2 changes: 1 addition & 1 deletion example/fundamentals/modules/8-diy-java-modules/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ object qux extends DiyJavaModule {
// label = "foo";
//
// "foo.bar.classPath" -> "foo.compile" [constraint=false];
// "foo.bar.classPath" -> "foo.classPath"
// "foo.sources" -> "foo.compile" -> "foo.classPath" -> "foo.assembly"
// "foo.mainClass" -> "foo.assembly"
// }
Expand All @@ -116,6 +115,7 @@ object qux extends DiyJavaModule {
// label = "qux";
//
// "qux.mainClass" -> "qux.assembly"
// "foo.bar.classPath" -> "foo.classPath"
// "foo.classPath" -> "qux.compile" [constraint=false];
// "foo.classPath" -> "qux.classPath"
// "qux.sources" -> "qux.compile" -> "qux.classPath" -> "qux.assembly"
Expand Down
2 changes: 1 addition & 1 deletion example/javalib/linting/3-palantirformat/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ error: ...palantirformat aborted due to format error(s) (or invalid plugin setti
> ./mill palantirformat --check # check should succeed now
...checking format in java sources ...
*/
// You can also use Palantir Java Format globally on all `JavaModule`s in your build by running
// You can also use Palantir Java Format globally on all ``JavaModule``s in your build by running
// `mill.javalib.palantirformat.PalantirFormatModule/`.

/** Usage
Expand Down
4 changes: 2 additions & 2 deletions example/javalib/module/8-annotation-processors/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ object bar extends JavaModule {

/** Usage

> ./mill bar.test
> ./mill bar.test
Test bar.HelloWorldTest.testSimple started
Test bar.HelloWorldTest.testSimple finished...
...

*/

// Many Java frameworks and libraries such as xref:javalib/web-examples#_micronaut_hello_world_app[Micronaut]
// or ErrorProne use annotation processors, and can be set up in this way.
// or ErrorProne use annotation processors, and can be set up in this way.
27 changes: 14 additions & 13 deletions example/javalib/publishing/5-jlink/build.mill
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// This example illustrates how to use Mill to generate a runtime image using the `jlink` tool.
// Starting with JDK 9, `jlink` bundles Java app code with a stripped-down version of the JVM.

//// SNIPPET:BUILD
package build
import mill._, javalib._
import mill.javalib.Assembly._
Expand All @@ -12,22 +11,21 @@ object foo extends JavaModule with JlinkModule {
def jlinkModuleVersion: T[Option[String]] = T { Option("1.0") }
def jlinkCompressLevel: T[String] = T { "2" }
}
//// SNIPPET:END

//
// Most of the work is done by the `trait JlinkModule` in two steps:

// 1.0. it uses the `jmod` tool to create a `jlink.jmod` file for the main Java module.
//
// * It uses the `jmod` tool to create a `jlink.jmod` file for the main Java module.
// The main Java module is typically the module containing the `mainClass`.

//
// If your build file doesn't explicitly specify a `mainClass`, `JlinkModule` will infer it from `JavaModule`, which is its parent trait.
// See xref:javalib/module-config.adoc#specifying-main-class[Specifying the Main Class] to learn more on how to influence the inference process.
// You can explicitly specify a `mainClass` like so in your build file:
//
// ```scala
// def mainClass: T[Option[String]] = { Some("com.foo.app.Main") }
// ```

//// SNIPPET:BUILD
// def mainClass: T[Option[String]] = { Option("com.foo.app.Main") }
//// SNIPPET:END

// 2.0. it then uses the `jlink` tool, to link the previously created `jlink.jmod` with a runtime image.
// * It then uses the `jlink` tool, to link the previously created `jlink.jmod` with a runtime image.

// With respect to the `jlinkCompressLevel` option, on recent builds of OpenJDK and its descendants,
// `jlink` will accept [`0`, `1`, `2`] but it will issue a deprecation warning.
Expand All @@ -37,11 +35,14 @@ object foo extends JavaModule with JlinkModule {
// as valid values for compression, with `0` being "no compression"
// and 2 being "ZIP compression".

/** Usage

// To use a specific JDK, first set your `JAVA_HOME` environment variable prior to running the build.

// ```
// export JAVA_HOME=/Users/mac/.sdkman/candidates/java/17.0.9-oracle/
// ```

/** Usage


> mill foo.jlinkAppImage

Expand Down
Loading

0 comments on commit 76b8f64

Please sign in to comment.