From 557d535265dcf93accc74fbc8beac56b857b3fc4 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 9 Sep 2025 13:40:02 +0800 Subject: [PATCH] Revert "Revert "Allow running standalone single-file scripts using Mill (#5820)"" This reverts commit 72db1f396dd1a6f6205228e7f0aef65c7412bd18. --- .editorconfig | 6 + build.mill | 2 +- core/constants/src/mill/constants/Util.java | 13 +- core/internal/cli/package.mill | 5 +- .../cli/src/mill/internal/MillCliConfig.scala | 5 + example/javalib/basic/5-single-file/Foo.java | 35 ++ .../javalib/basic/5-single-file/build.mill | 30 ++ example/javalib/module/1-single-file/Bar.java | 17 + .../javalib/module/1-single-file/build.mill | 24 ++ .../build.mill | 0 .../custom-resources/MyOtherResource.txt | 0 .../custom-src/Foo2.java | 0 .../resources/MyResource.txt | 0 .../src/foo/Foo.java | 0 .../build.mill | 0 .../src/foo/Foo.java | 0 .../build.mill | 0 .../build.mill | 0 .../src/foo/Foo.java | 0 example/kotlinlib/basic/5-single-file/Foo.kt | 20 + .../kotlinlib/basic/5-single-file/build.mill | 29 ++ example/kotlinlib/module/1-single-file/Bar.kt | 15 + .../kotlinlib/module/1-single-file/build.mill | 23 ++ .../10-dependency-injection}/build.mill | 0 .../dagger/src/main/Main.kt | 0 .../dagger/src/main/NumberApp.kt | 0 .../dagger/src/main/NumberGenerator.kt | 0 .../dagger/src/main/NumberGeneratorModule.kt | 0 .../dagger/src/main/NumberService.kt | 0 .../dagger/src/main/RandomNumberGenerator.kt | 0 .../test/src/ConstantNumberGenerator.kt | 0 .../dagger/test/src/DemoComponent.kt | 0 .../dagger/test/src/NumberTestModule.kt | 0 .../dagger/test/src/TestApp.kt | 0 .../TestConstantNumberGeneratorInjection.kt | 0 .../build.mill | 0 .../custom-resources/MyOtherResource.txt | 0 .../custom-src/Foo2.kt | 0 .../resources/MyResource.txt | 0 .../src/foo/Foo.kt | 0 .../build.mill | 0 .../src/foo/Foo.kt | 0 .../build.mill | 0 .../build.mill | 0 .../src/foo/Foo.kt | 0 example/package.mill | 3 +- .../scalalib/basic/5-single-file/Foo.scala | 18 + .../scalalib/basic/5-single-file/build.mill | 50 +++ .../scalalib/module/1-single-file/Bar.scala | 17 + .../scalalib/module/1-single-file/build.mill | 40 ++ .../build.mill | 0 .../custom-resources/MyOtherResource.txt | 0 .../custom-src/Foo2.scala | 0 .../resources/MyResource.txt | 0 .../src/Foo.scala | 0 .../build.mill | 0 .../src/Foo.scala | 0 .../build.mill | 0 .../build.mill | 0 .../src/Foo.scala | 0 .../mill/javalib/publish/JsonFormatters.scala | 24 +- .../src/mill/javalib/publish/Licence.scala | 388 +++++++++++++++++- .../src/mill/javalib/publish/Pom.scala | 1 + .../src/mill/javalib/publish/model.scala | 7 +- .../mill/tabcomplete/TabCompleteTests.scala | 4 +- .../src/mill/daemon/MillBuildBootstrap.scala | 228 ++++++---- runner/daemon/src/mill/daemon/MillMain0.scala | 42 +- runner/daemon/src/mill/daemon/Watching.scala | 10 +- runner/meta/package.mill | 3 +- runner/meta/src/mill/meta/ScriptModule.scala | 37 ++ test/Foo.java | 35 ++ .../modules/ROOT/pages/cli/build-header.adoc | 9 +- website/docs/modules/ROOT/pages/index.adoc | 6 +- .../modules/ROOT/pages/javalib/intro.adoc | 6 + .../ROOT/pages/javalib/module-config.adoc | 33 +- .../modules/ROOT/pages/kotlinlib/intro.adoc | 5 + .../ROOT/pages/kotlinlib/module-config.adoc | 32 +- .../modules/ROOT/pages/scalalib/intro.adoc | 6 +- .../ROOT/pages/scalalib/module-config.adoc | 26 +- 79 files changed, 1083 insertions(+), 171 deletions(-) create mode 100644 example/javalib/basic/5-single-file/Foo.java create mode 100644 example/javalib/basic/5-single-file/build.mill create mode 100644 example/javalib/module/1-single-file/Bar.java create mode 100644 example/javalib/module/1-single-file/build.mill rename example/javalib/module/{1-common-config => 2-common-config}/build.mill (100%) rename example/javalib/module/{1-common-config => 2-common-config}/custom-resources/MyOtherResource.txt (100%) rename example/javalib/module/{1-common-config => 2-common-config}/custom-src/Foo2.java (100%) rename example/javalib/module/{1-common-config => 2-common-config}/resources/MyResource.txt (100%) rename example/javalib/module/{1-common-config => 2-common-config}/src/foo/Foo.java (100%) rename example/javalib/module/{2-custom-tasks => 3-custom-tasks}/build.mill (100%) rename example/javalib/module/{2-custom-tasks => 3-custom-tasks}/src/foo/Foo.java (100%) rename example/javalib/module/{3-generated-sources => 4-generated-sources}/build.mill (100%) rename example/javalib/module/{4-compilation-execution-flags => 5-compilation-execution-flags}/build.mill (100%) rename example/javalib/module/{4-compilation-execution-flags => 5-compilation-execution-flags}/src/foo/Foo.java (100%) create mode 100644 example/kotlinlib/basic/5-single-file/Foo.kt create mode 100644 example/kotlinlib/basic/5-single-file/build.mill create mode 100644 example/kotlinlib/module/1-single-file/Bar.kt create mode 100644 example/kotlinlib/module/1-single-file/build.mill rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/build.mill (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/src/main/Main.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/src/main/NumberApp.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/src/main/NumberGenerator.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/src/main/NumberGeneratorModule.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/src/main/NumberService.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/src/main/RandomNumberGenerator.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/test/src/ConstantNumberGenerator.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/test/src/DemoComponent.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/test/src/NumberTestModule.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/test/src/TestApp.kt (100%) rename example/kotlinlib/{basic/7-dependency-injection => module/10-dependency-injection}/dagger/test/src/TestConstantNumberGeneratorInjection.kt (100%) rename example/kotlinlib/module/{1-common-config => 2-common-config}/build.mill (100%) rename example/kotlinlib/module/{1-common-config => 2-common-config}/custom-resources/MyOtherResource.txt (100%) rename example/kotlinlib/module/{1-common-config => 2-common-config}/custom-src/Foo2.kt (100%) rename example/kotlinlib/module/{1-common-config => 2-common-config}/resources/MyResource.txt (100%) rename example/kotlinlib/module/{1-common-config => 2-common-config}/src/foo/Foo.kt (100%) rename example/kotlinlib/module/{2-custom-tasks => 3-custom-tasks}/build.mill (100%) rename example/kotlinlib/module/{2-custom-tasks => 3-custom-tasks}/src/foo/Foo.kt (100%) rename example/kotlinlib/module/{3-generated-sources => 4-generated-sources}/build.mill (100%) rename example/kotlinlib/module/{4-compilation-execution-flags => 5-compilation-execution-flags}/build.mill (100%) rename example/kotlinlib/module/{4-compilation-execution-flags => 5-compilation-execution-flags}/src/foo/Foo.kt (100%) create mode 100644 example/scalalib/basic/5-single-file/Foo.scala create mode 100644 example/scalalib/basic/5-single-file/build.mill create mode 100644 example/scalalib/module/1-single-file/Bar.scala create mode 100644 example/scalalib/module/1-single-file/build.mill rename example/scalalib/module/{1-common-config => 2-common-config}/build.mill (100%) rename example/scalalib/module/{1-common-config => 2-common-config}/custom-resources/MyOtherResource.txt (100%) rename example/scalalib/module/{1-common-config => 2-common-config}/custom-src/Foo2.scala (100%) rename example/scalalib/module/{1-common-config => 2-common-config}/resources/MyResource.txt (100%) rename example/scalalib/module/{1-common-config => 2-common-config}/src/Foo.scala (100%) rename example/scalalib/module/{2-custom-tasks => 3-custom-tasks}/build.mill (100%) rename example/scalalib/module/{2-custom-tasks => 3-custom-tasks}/src/Foo.scala (100%) rename example/scalalib/module/{3-generated-sources => 4-generated-sources}/build.mill (100%) rename example/scalalib/module/{4-compilation-execution-flags => 5-compilation-execution-flags}/build.mill (100%) rename example/scalalib/module/{4-compilation-execution-flags => 5-compilation-execution-flags}/src/Foo.scala (100%) create mode 100644 runner/meta/src/mill/meta/ScriptModule.scala create mode 100644 test/Foo.java diff --git a/.editorconfig b/.editorconfig index 2f2d99c5dd23..2d21be2e1a2e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,6 +18,12 @@ indent_size = 2 ktlint_code_style = intellij_idea ktlint_standard_no-wildcard-imports = disabled +[example/kotlinlib/basic/5-single-file/**/*] +ktlint = disabled + +[example/kotlinlib/module/1-single-file/**/*] +ktlint = disabled + [example/kotlinlib/linting/**/*] ktlint = disabled diff --git a/build.mill b/build.mill index f140f012c605..a4a5a930fafc 100644 --- a/build.mill +++ b/build.mill @@ -1,4 +1,4 @@ -//| mill-version: 1.0.4-26-a6e4c1 +//| mill-version: 1.0.4-38-cbb9e8 //| mill-jvm-opts: ["-XX:NonProfiledCodeHeapSize=250m", "-XX:ReservedCodeCacheSize=500m"] //| mill-opts: ["--jobs=0.5C"] diff --git a/core/constants/src/mill/constants/Util.java b/core/constants/src/mill/constants/Util.java index ab2bcc1078aa..c569a90874a2 100644 --- a/core/constants/src/mill/constants/Util.java +++ b/core/constants/src/mill/constants/Util.java @@ -5,6 +5,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -84,15 +86,20 @@ private static String throwBuildHeaderError( + ": " + line + "\n" + msg); } - public static String readBuildHeader(java.nio.file.Path buildFile, String errorFileName) { + public static String readBuildHeader(Path buildFile, String errorFileName) { + return readBuildHeader(buildFile, errorFileName, false); + } + + public static String readBuildHeader( + Path buildFile, String errorFileName, boolean allowNonBuild) { try { - java.util.List lines = java.nio.file.Files.readAllLines(buildFile); + java.util.List lines = Files.readAllLines(buildFile); boolean readingBuildHeader = true; java.util.List output = new ArrayList<>(); for (int i = 0; i < lines.size(); i++) { String line = lines.get(i); if (!line.startsWith("//|")) readingBuildHeader = false; - else if (!buildFile.getFileName().toString().startsWith("build.")) { + else if (!allowNonBuild && !buildFile.getFileName().toString().startsWith("build.")) { throwBuildHeaderError( errorFileName, i, diff --git a/core/internal/cli/package.mill b/core/internal/cli/package.mill index f5f86646c342..caeeed1978ab 100644 --- a/core/internal/cli/package.mill +++ b/core/internal/cli/package.mill @@ -9,8 +9,5 @@ import millbuild.* object `package` extends MillPublishScalaModule { def moduleDeps = Seq(build.libs.util) - def mvnDeps = Seq( - Deps.millModuledefs, - Deps.mainargs - ) + def mvnDeps = Seq(Deps.mainargs) } diff --git a/core/internal/cli/src/mill/internal/MillCliConfig.scala b/core/internal/cli/src/mill/internal/MillCliConfig.scala index b5e2e386869f..f60be97992f0 100644 --- a/core/internal/cli/src/mill/internal/MillCliConfig.scala +++ b/core/internal/cli/src/mill/internal/MillCliConfig.scala @@ -128,6 +128,11 @@ case class MillCliConfig( doc = """Runs Mill in tab-completion mode""" ) tabComplete: Flag = Flag(), + @arg( + short = 'f', + doc = """Select the build.mill file or Java/Scala/Kotlin script file to run""" + ) + file: Option[os.Path] = None, // ==================== DEPRECATED CLI FLAGS ==================== @arg(hidden = true, short = 'h', doc = "Unsupported") diff --git a/example/javalib/basic/5-single-file/Foo.java b/example/javalib/basic/5-single-file/Foo.java new file mode 100644 index 000000000000..18a667d13b99 --- /dev/null +++ b/example/javalib/basic/5-single-file/Foo.java @@ -0,0 +1,35 @@ +//| mvnDeps: +//| - "net.sourceforge.argparse4j:argparse4j:0.9.0" +//| - "org.thymeleaf:thymeleaf:3.1.1.RELEASE" +import net.sourceforge.argparse4j.ArgumentParsers; +import net.sourceforge.argparse4j.inf.ArgumentParser; +import net.sourceforge.argparse4j.inf.Namespace; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +public class Foo { + public static String generateHtml(String text) { + Context context = new Context(); + context.setVariable("text", text); + return new TemplateEngine().process("

", context); + } + + public static void main(String[] args) { + ArgumentParser parser = ArgumentParsers.newFor("template") + .build() + .defaultHelp(true) + .description("Inserts text into a HTML template"); + + parser.addArgument("-t", "--text").required(true).help("text to insert"); + + Namespace ns = null; + try { + ns = parser.parseArgs(args); + } catch (Exception e) { + System.out.println(e.getMessage()); + System.exit(1); + } + + System.out.println(generateHtml(ns.getString("text"))); + } +} diff --git a/example/javalib/basic/5-single-file/build.mill b/example/javalib/basic/5-single-file/build.mill new file mode 100644 index 000000000000..49f499e7ea29 --- /dev/null +++ b/example/javalib/basic/5-single-file/build.mill @@ -0,0 +1,30 @@ +//// SNIPPET:FILE +/** See Also: Foo.java */ +/** Usage +> ./mill Foo.java --text hello +compiling 1 Java source to... +

hello

+*/ + +/** Usage +> ./mill -f Foo.java run --text hello +

hello

+*/ + +//// SNIPPET:END +//// SNIPPET:MORE + +/** Usage +> ./mill -f Foo.java show assembly # show the output of the assembly task +".../out/Foo.java/assembly.dest/out.jar" + +> java -jar ./out/Foo.java/assembly.dest/out.jar --text hello +

hello

+ +> ./out/Foo.java/assembly.dest/out.jar --text hello # mac/linux +

hello

+ + +*/ + +//// SNIPPET:END diff --git a/example/javalib/module/1-single-file/Bar.java b/example/javalib/module/1-single-file/Bar.java new file mode 100644 index 000000000000..4b608e8ee807 --- /dev/null +++ b/example/javalib/module/1-single-file/Bar.java @@ -0,0 +1,17 @@ +//| jvmId: "graalvm-community:24" +//| nativeImageOptions: ["--no-fallback"] +//| publishVersion: "0.0.1" +//| artifactName: "example" +//| pomSettings: +//| description: "Example" +//| organization: "com.lihaoyi" +//| url: "https://github.com/com.lihaoyi/example" +//| licenses: ["MIT"] +//| versionControl: "https://github.com/com.lihaoyi/example" +//| developers: [{"name": "Li Haoyi", "email": "example@example.com"}] + +public class Bar { + public static void main(String[] args) { + System.out.println("Hello Graal Native: " + System.getProperty("java.version")); + } +} diff --git a/example/javalib/module/1-single-file/build.mill b/example/javalib/module/1-single-file/build.mill new file mode 100644 index 000000000000..8a0abcdda1fa --- /dev/null +++ b/example/javalib/module/1-single-file/build.mill @@ -0,0 +1,24 @@ +//// SNIPPET:LAST + +/** See Also: Bar.java */ +/** Usage + +> ./mill -f Bar.java nativeImage + +> out/Bar.java/nativeImage.dest/native-executable +Hello Graal Native: 24... + +> ./mill -f Bar.java publishLocal +Publishing Artifact(com.lihaoyi,example...,0.0.1) to ivy repo ... + +*/ + +// Apart from publishing locally, you can also publish this single-file project to +// Sonatype Maven Central via: +// +// [source,console] +// ---- +// > ./mill -f Bar.java mill.javalib.SonatypeCentralPublishModule/ +// ---- + +//// SNIPPET:END diff --git a/example/javalib/module/1-common-config/build.mill b/example/javalib/module/2-common-config/build.mill similarity index 100% rename from example/javalib/module/1-common-config/build.mill rename to example/javalib/module/2-common-config/build.mill diff --git a/example/javalib/module/1-common-config/custom-resources/MyOtherResource.txt b/example/javalib/module/2-common-config/custom-resources/MyOtherResource.txt similarity index 100% rename from example/javalib/module/1-common-config/custom-resources/MyOtherResource.txt rename to example/javalib/module/2-common-config/custom-resources/MyOtherResource.txt diff --git a/example/javalib/module/1-common-config/custom-src/Foo2.java b/example/javalib/module/2-common-config/custom-src/Foo2.java similarity index 100% rename from example/javalib/module/1-common-config/custom-src/Foo2.java rename to example/javalib/module/2-common-config/custom-src/Foo2.java diff --git a/example/javalib/module/1-common-config/resources/MyResource.txt b/example/javalib/module/2-common-config/resources/MyResource.txt similarity index 100% rename from example/javalib/module/1-common-config/resources/MyResource.txt rename to example/javalib/module/2-common-config/resources/MyResource.txt diff --git a/example/javalib/module/1-common-config/src/foo/Foo.java b/example/javalib/module/2-common-config/src/foo/Foo.java similarity index 100% rename from example/javalib/module/1-common-config/src/foo/Foo.java rename to example/javalib/module/2-common-config/src/foo/Foo.java diff --git a/example/javalib/module/2-custom-tasks/build.mill b/example/javalib/module/3-custom-tasks/build.mill similarity index 100% rename from example/javalib/module/2-custom-tasks/build.mill rename to example/javalib/module/3-custom-tasks/build.mill diff --git a/example/javalib/module/2-custom-tasks/src/foo/Foo.java b/example/javalib/module/3-custom-tasks/src/foo/Foo.java similarity index 100% rename from example/javalib/module/2-custom-tasks/src/foo/Foo.java rename to example/javalib/module/3-custom-tasks/src/foo/Foo.java diff --git a/example/javalib/module/3-generated-sources/build.mill b/example/javalib/module/4-generated-sources/build.mill similarity index 100% rename from example/javalib/module/3-generated-sources/build.mill rename to example/javalib/module/4-generated-sources/build.mill diff --git a/example/javalib/module/4-compilation-execution-flags/build.mill b/example/javalib/module/5-compilation-execution-flags/build.mill similarity index 100% rename from example/javalib/module/4-compilation-execution-flags/build.mill rename to example/javalib/module/5-compilation-execution-flags/build.mill diff --git a/example/javalib/module/4-compilation-execution-flags/src/foo/Foo.java b/example/javalib/module/5-compilation-execution-flags/src/foo/Foo.java similarity index 100% rename from example/javalib/module/4-compilation-execution-flags/src/foo/Foo.java rename to example/javalib/module/5-compilation-execution-flags/src/foo/Foo.java diff --git a/example/kotlinlib/basic/5-single-file/Foo.kt b/example/kotlinlib/basic/5-single-file/Foo.kt new file mode 100644 index 000000000000..22b38cfcf340 --- /dev/null +++ b/example/kotlinlib/basic/5-single-file/Foo.kt @@ -0,0 +1,20 @@ +//| mvnDeps: +//| - "com.github.ajalt.clikt:clikt:4.4.0" +//| - "org.jetbrains.kotlinx:kotlinx-html:0.11.0" +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.options.required +import kotlinx.html.h1 +import kotlinx.html.stream.createHTML + +class Foo : CliktCommand() { + val text by option("-t", "--text", help = "text to insert").required() + + override fun run() { + echo(generateHtml(text)) + } +} + +fun generateHtml(text: String): String = createHTML(prettyPrint = false).h1 { text(text) }.toString() + +fun main(args: Array) = Foo().main(args) diff --git a/example/kotlinlib/basic/5-single-file/build.mill b/example/kotlinlib/basic/5-single-file/build.mill new file mode 100644 index 000000000000..fd7d730bcfd3 --- /dev/null +++ b/example/kotlinlib/basic/5-single-file/build.mill @@ -0,0 +1,29 @@ +//// SNIPPET:FILE +/** See Also: Foo.kt */ +/** Usage +> ./mill Foo.kt --text hello +Compiling 1 Kotlin sources to... +

hello

+*/ + +//// SNIPPET:END +//// SNIPPET:MORE + +/** Usage +> ./mill -f Foo.kt run --text hello +

hello

+*/ + +/** Usage +> ./mill -f Foo.kt show assembly # show the output of the assembly task +".../out/Foo.kt/assembly.dest/out.jar" + +> java -jar ./out/Foo.kt/assembly.dest/out.jar --text hello +

hello

+ +> ./out/Foo.kt/assembly.dest/out.jar --text hello # mac/linux +

hello

+ +*/ + +//// SNIPPET:END diff --git a/example/kotlinlib/module/1-single-file/Bar.kt b/example/kotlinlib/module/1-single-file/Bar.kt new file mode 100644 index 000000000000..8d4920ae08d7 --- /dev/null +++ b/example/kotlinlib/module/1-single-file/Bar.kt @@ -0,0 +1,15 @@ +//| jvmId: "graalvm-community:24" +//| nativeImageOptions: ["--no-fallback"] +//| publishVersion: "0.0.1" +//| artifactName: "example" +//| pomSettings: +//| description: "Example" +//| organization: "com.lihaoyi" +//| url: "https://github.com/com.lihaoyi/example" +//| licenses: ["MIT"] +//| versionControl: "https://github.com/com.lihaoyi/example" +//| developers: [{"name": "Li Haoyi", "email": "example@example.com"}] + +fun main(args: Array) { + println("Hello Graal Native: " + System.getProperty("java.version")) +} diff --git a/example/kotlinlib/module/1-single-file/build.mill b/example/kotlinlib/module/1-single-file/build.mill new file mode 100644 index 000000000000..6f4ac53db59b --- /dev/null +++ b/example/kotlinlib/module/1-single-file/build.mill @@ -0,0 +1,23 @@ +//// SNIPPET:LAST +/** See Also: Bar.kt */ +/** Usage + +> ./mill -f Bar.kt nativeImage + +> out/Bar.kt/nativeImage.dest/native-executable +Hello Graal Native: 24... + +> ./mill -f Bar.kt publishLocal +Publishing Artifact(com.lihaoyi,example...,0.0.1) to ivy repo ... + +*/ + +// Apart from publishing locally, you can also publish this single-file project to +// Sonatype Maven Central via: +// +// [source,console] +// ---- +// > ./mill -f Bar.kt mill.javalib.SonatypeCentralPublishModule/ +// ---- + +//// SNIPPET:END diff --git a/example/kotlinlib/basic/7-dependency-injection/build.mill b/example/kotlinlib/module/10-dependency-injection/build.mill similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/build.mill rename to example/kotlinlib/module/10-dependency-injection/build.mill diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/src/main/Main.kt b/example/kotlinlib/module/10-dependency-injection/dagger/src/main/Main.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/src/main/Main.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/src/main/Main.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberApp.kt b/example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberApp.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberApp.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberApp.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberGenerator.kt b/example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberGenerator.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberGenerator.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberGenerator.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberGeneratorModule.kt b/example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberGeneratorModule.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberGeneratorModule.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberGeneratorModule.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberService.kt b/example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberService.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/src/main/NumberService.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/src/main/NumberService.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/src/main/RandomNumberGenerator.kt b/example/kotlinlib/module/10-dependency-injection/dagger/src/main/RandomNumberGenerator.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/src/main/RandomNumberGenerator.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/src/main/RandomNumberGenerator.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/test/src/ConstantNumberGenerator.kt b/example/kotlinlib/module/10-dependency-injection/dagger/test/src/ConstantNumberGenerator.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/test/src/ConstantNumberGenerator.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/test/src/ConstantNumberGenerator.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/test/src/DemoComponent.kt b/example/kotlinlib/module/10-dependency-injection/dagger/test/src/DemoComponent.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/test/src/DemoComponent.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/test/src/DemoComponent.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/test/src/NumberTestModule.kt b/example/kotlinlib/module/10-dependency-injection/dagger/test/src/NumberTestModule.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/test/src/NumberTestModule.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/test/src/NumberTestModule.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/test/src/TestApp.kt b/example/kotlinlib/module/10-dependency-injection/dagger/test/src/TestApp.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/test/src/TestApp.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/test/src/TestApp.kt diff --git a/example/kotlinlib/basic/7-dependency-injection/dagger/test/src/TestConstantNumberGeneratorInjection.kt b/example/kotlinlib/module/10-dependency-injection/dagger/test/src/TestConstantNumberGeneratorInjection.kt similarity index 100% rename from example/kotlinlib/basic/7-dependency-injection/dagger/test/src/TestConstantNumberGeneratorInjection.kt rename to example/kotlinlib/module/10-dependency-injection/dagger/test/src/TestConstantNumberGeneratorInjection.kt diff --git a/example/kotlinlib/module/1-common-config/build.mill b/example/kotlinlib/module/2-common-config/build.mill similarity index 100% rename from example/kotlinlib/module/1-common-config/build.mill rename to example/kotlinlib/module/2-common-config/build.mill diff --git a/example/kotlinlib/module/1-common-config/custom-resources/MyOtherResource.txt b/example/kotlinlib/module/2-common-config/custom-resources/MyOtherResource.txt similarity index 100% rename from example/kotlinlib/module/1-common-config/custom-resources/MyOtherResource.txt rename to example/kotlinlib/module/2-common-config/custom-resources/MyOtherResource.txt diff --git a/example/kotlinlib/module/1-common-config/custom-src/Foo2.kt b/example/kotlinlib/module/2-common-config/custom-src/Foo2.kt similarity index 100% rename from example/kotlinlib/module/1-common-config/custom-src/Foo2.kt rename to example/kotlinlib/module/2-common-config/custom-src/Foo2.kt diff --git a/example/kotlinlib/module/1-common-config/resources/MyResource.txt b/example/kotlinlib/module/2-common-config/resources/MyResource.txt similarity index 100% rename from example/kotlinlib/module/1-common-config/resources/MyResource.txt rename to example/kotlinlib/module/2-common-config/resources/MyResource.txt diff --git a/example/kotlinlib/module/1-common-config/src/foo/Foo.kt b/example/kotlinlib/module/2-common-config/src/foo/Foo.kt similarity index 100% rename from example/kotlinlib/module/1-common-config/src/foo/Foo.kt rename to example/kotlinlib/module/2-common-config/src/foo/Foo.kt diff --git a/example/kotlinlib/module/2-custom-tasks/build.mill b/example/kotlinlib/module/3-custom-tasks/build.mill similarity index 100% rename from example/kotlinlib/module/2-custom-tasks/build.mill rename to example/kotlinlib/module/3-custom-tasks/build.mill diff --git a/example/kotlinlib/module/2-custom-tasks/src/foo/Foo.kt b/example/kotlinlib/module/3-custom-tasks/src/foo/Foo.kt similarity index 100% rename from example/kotlinlib/module/2-custom-tasks/src/foo/Foo.kt rename to example/kotlinlib/module/3-custom-tasks/src/foo/Foo.kt diff --git a/example/kotlinlib/module/3-generated-sources/build.mill b/example/kotlinlib/module/4-generated-sources/build.mill similarity index 100% rename from example/kotlinlib/module/3-generated-sources/build.mill rename to example/kotlinlib/module/4-generated-sources/build.mill diff --git a/example/kotlinlib/module/4-compilation-execution-flags/build.mill b/example/kotlinlib/module/5-compilation-execution-flags/build.mill similarity index 100% rename from example/kotlinlib/module/4-compilation-execution-flags/build.mill rename to example/kotlinlib/module/5-compilation-execution-flags/build.mill diff --git a/example/kotlinlib/module/4-compilation-execution-flags/src/foo/Foo.kt b/example/kotlinlib/module/5-compilation-execution-flags/src/foo/Foo.kt similarity index 100% rename from example/kotlinlib/module/4-compilation-execution-flags/src/foo/Foo.kt rename to example/kotlinlib/module/5-compilation-execution-flags/src/foo/Foo.kt diff --git a/example/package.mill b/example/package.mill index d6be7fe9ef5a..e628b318cf15 100644 --- a/example/package.mill +++ b/example/package.mill @@ -250,9 +250,10 @@ object `package` extends Module { .map { case (s"see:$path", txt) => // avoid .stripMargin, as the embedded content may contain the margin symbol + val lang = os.FilePath(path).ext s""" .$path ({mill-example-url}/$examplePath/$path[browse]) -[source,scala,subs="attributes,verbatim"] +[source,$lang,subs="attributes,verbatim"] ---- $txt ----""" diff --git a/example/scalalib/basic/5-single-file/Foo.scala b/example/scalalib/basic/5-single-file/Foo.scala new file mode 100644 index 000000000000..141ffb781c30 --- /dev/null +++ b/example/scalalib/basic/5-single-file/Foo.scala @@ -0,0 +1,18 @@ +//| mvnDeps: +//| - "com.lihaoyi::scalatags:0.13.1" +//| - "com.lihaoyi::mainargs:0.7.6" +import scalatags.Text.all.* +import mainargs.{main, ParserForMethods} + +object Foo { + def generateHtml(text: String) = { + h1(text).toString + } + + @main + def main(text: String) = { + println(generateHtml(text)) + } + + def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) +} diff --git a/example/scalalib/basic/5-single-file/build.mill b/example/scalalib/basic/5-single-file/build.mill new file mode 100644 index 000000000000..7fcd80aedab3 --- /dev/null +++ b/example/scalalib/basic/5-single-file/build.mill @@ -0,0 +1,50 @@ +// Mill also allows you to run single-file {language} programs easily from the command-line, +// even those that contain third-party dependencies or other such configuration. These can be +// useful as a replacement for Bash scripts, letting you write small scripts or programs +// in {language} with full access to third-party libraries and other build-tool features. +// +// For example, given the single-file program below, it can be run directly using Mill: + +//// SNIPPET:FILE +/** See Also: Foo.scala */ + +/** Usage +> ./mill Foo.scala --text hello +compiling 1 Scala source to... +

hello

+*/ + +//// SNIPPET:END + +// The `./mill Foo.{language-ext}` syntax is shorthand for `./mill -f Foo.{language-ext} run` +// or `./mill --file Foo.{language-ext} run`, which can also be passed explicitly. The +// explicit `-f`/`--file` also allows you to call other tasks on the single-file project, +// e.g. bundling it into an assembly: + +//// SNIPPET:MORE + +/** Usage +> ./mill -f Foo.scala run --text hello +

hello

+*/ + +/** Usage +> ./mill -f Foo.scala show assembly # show the output of the assembly task +".../out/Foo.scala/assembly.dest/out.jar" + +> java -jar ./out/Foo.scala/assembly.dest/out.jar --text hello +

hello

+ +> ./out/Foo.scala/assembly.dest/out.jar --text hello # mac/linux +

hello

+ +*/ + +//// SNIPPET:END + +// For more details on single-file projects, see +// xref:{language-small}lib/module-config.adoc#_configuring_single_file_projects[Configuring Single-File Projects] +// The rest of the examples below discuss the Mill config for building larger projects +// beyond the single-file project format discussed above, using a dedicated `build.mill` +// file to provide additional flexibility in setting up your project. +// diff --git a/example/scalalib/module/1-single-file/Bar.scala b/example/scalalib/module/1-single-file/Bar.scala new file mode 100644 index 000000000000..d0d3d12434b6 --- /dev/null +++ b/example/scalalib/module/1-single-file/Bar.scala @@ -0,0 +1,17 @@ +//| jvmId: "graalvm-community:24" +//| nativeImageOptions: ["--no-fallback"] +//| publishVersion: "0.0.1" +//| artifactName: "example" +//| pomSettings: +//| description: "Example" +//| organization: "com.lihaoyi" +//| url: "https://github.com/com.lihaoyi/example" +//| licenses: ["MIT"] +//| versionControl: "https://github.com/com.lihaoyi/example" +//| developers: [{"name": "Li Haoyi", "email": "example@example.com"}] + +object Bar { + def main(args: Array[String]): Unit = { + println("Hello Graal Native: " + System.getProperty("java.version")) + } +} diff --git a/example/scalalib/module/1-single-file/build.mill b/example/scalalib/module/1-single-file/build.mill new file mode 100644 index 000000000000..8a6172d9854c --- /dev/null +++ b/example/scalalib/module/1-single-file/build.mill @@ -0,0 +1,40 @@ +// Mill Single-File Projects have the full flexibility of the Mill build tool, just configured +// using the YAML xref:cli/build-header.adoc[build header] syntax rather than a separate +// `build.mill` file. That means you can xref:fundamentals/configuring-jvm-versions.adoc[configure the JVM version], +// xref:javalib/module-config.adoc#_compilation_execution_flags[compile flags or runtime flags], create +// xref:javalib/publishing.adoc#_building_executable_assemblies_with_assemblymodule[Executable Assemblies] +// or xref:javalib/publishing.adoc#_building_native_image_binaries_with_graal_vm[Graal Native Images], +// xref:javalib/publishing.adoc#_publishing_to_sonatype_maven_central[Publishing to Maven Central] +// etc. +// +// The example below shows a few of those options configured in the YAML build header +// of a single-file project, and then made of use from the command line: + +//// SNIPPET:LAST + +/** See Also: Bar.scala */ +/** Usage + +> ./mill -f Bar.scala nativeImage + +> out/Bar.scala/nativeImage.dest/native-executable +Hello Graal Native: 24... + +> ./mill -f Bar.scala publishLocal +Publishing Artifact(com.lihaoyi,example...,0.0.1) to ivy repo ... + +*/ +// Apart from publishing locally, you can also publish this single-file project to +// Sonatype Maven Central via: +// +// [source,console] +// ---- +// > ./mill -f Bar.scala mill.javalib.SonatypeCentralPublishModule/ +// ---- + +//// SNIPPET:END + +// Most configuration ``def``s in Mill can be used to configure single-file projects, and +// most tasks and commands can also be used as well. This gives you a lot of flexibility +// in working with your single-file project until it becomes complex enough to need +// a dedicated `build.mill` file. diff --git a/example/scalalib/module/1-common-config/build.mill b/example/scalalib/module/2-common-config/build.mill similarity index 100% rename from example/scalalib/module/1-common-config/build.mill rename to example/scalalib/module/2-common-config/build.mill diff --git a/example/scalalib/module/1-common-config/custom-resources/MyOtherResource.txt b/example/scalalib/module/2-common-config/custom-resources/MyOtherResource.txt similarity index 100% rename from example/scalalib/module/1-common-config/custom-resources/MyOtherResource.txt rename to example/scalalib/module/2-common-config/custom-resources/MyOtherResource.txt diff --git a/example/scalalib/module/1-common-config/custom-src/Foo2.scala b/example/scalalib/module/2-common-config/custom-src/Foo2.scala similarity index 100% rename from example/scalalib/module/1-common-config/custom-src/Foo2.scala rename to example/scalalib/module/2-common-config/custom-src/Foo2.scala diff --git a/example/scalalib/module/1-common-config/resources/MyResource.txt b/example/scalalib/module/2-common-config/resources/MyResource.txt similarity index 100% rename from example/scalalib/module/1-common-config/resources/MyResource.txt rename to example/scalalib/module/2-common-config/resources/MyResource.txt diff --git a/example/scalalib/module/1-common-config/src/Foo.scala b/example/scalalib/module/2-common-config/src/Foo.scala similarity index 100% rename from example/scalalib/module/1-common-config/src/Foo.scala rename to example/scalalib/module/2-common-config/src/Foo.scala diff --git a/example/scalalib/module/2-custom-tasks/build.mill b/example/scalalib/module/3-custom-tasks/build.mill similarity index 100% rename from example/scalalib/module/2-custom-tasks/build.mill rename to example/scalalib/module/3-custom-tasks/build.mill diff --git a/example/scalalib/module/2-custom-tasks/src/Foo.scala b/example/scalalib/module/3-custom-tasks/src/Foo.scala similarity index 100% rename from example/scalalib/module/2-custom-tasks/src/Foo.scala rename to example/scalalib/module/3-custom-tasks/src/Foo.scala diff --git a/example/scalalib/module/3-generated-sources/build.mill b/example/scalalib/module/4-generated-sources/build.mill similarity index 100% rename from example/scalalib/module/3-generated-sources/build.mill rename to example/scalalib/module/4-generated-sources/build.mill diff --git a/example/scalalib/module/4-compilation-execution-flags/build.mill b/example/scalalib/module/5-compilation-execution-flags/build.mill similarity index 100% rename from example/scalalib/module/4-compilation-execution-flags/build.mill rename to example/scalalib/module/5-compilation-execution-flags/build.mill diff --git a/example/scalalib/module/4-compilation-execution-flags/src/Foo.scala b/example/scalalib/module/5-compilation-execution-flags/src/Foo.scala similarity index 100% rename from example/scalalib/module/4-compilation-execution-flags/src/Foo.scala rename to example/scalalib/module/5-compilation-execution-flags/src/Foo.scala diff --git a/libs/javalib/src/mill/javalib/publish/JsonFormatters.scala b/libs/javalib/src/mill/javalib/publish/JsonFormatters.scala index aae67fa167cc..493f39ded0b5 100644 --- a/libs/javalib/src/mill/javalib/publish/JsonFormatters.scala +++ b/libs/javalib/src/mill/javalib/publish/JsonFormatters.scala @@ -5,8 +5,28 @@ import upickle.{ReadWriter => RW} trait JsonFormatters { implicit lazy val artifactFormat: RW[Artifact] = upickle.macroRW implicit lazy val developerFormat: RW[Developer] = upickle.macroRW - implicit lazy val licenseFormat: RW[License] = upickle.macroRW - implicit lazy val versionControlFormat: RW[VersionControl] = upickle.macroRW + implicit lazy val licenseFormat: RW[License] = upickle.readwriter[ujson.Value].bimap( + v => upickle.writeJs(v)(using upickle.macroRW[License]), + { + case ujson.Str(s) => + License.knownMap.getOrElse( + s, + sys.error( + s"Unknown License: `$s`, needs to be one of " + + License.knownMap.keys.mkString(", ") + ) + ) + case v => upickle.read(v)(using upickle.macroRW[License]) + } + ) + implicit lazy val versionControlFormat: RW[VersionControl] = + upickle.readwriter[ujson.Value].bimap( + v => upickle.writeJs(v)(using upickle.macroRW[VersionControl]), + { + case ujson.Str(s) => VersionControl(browsableRepository = Some(s)) + case v => upickle.read(v)(using upickle.macroRW[VersionControl]) + } + ) implicit lazy val pomSettingsFormat: RW[PomSettings] = upickle.macroRW } object JsonFormatters extends JsonFormatters diff --git a/libs/javalib/src/mill/javalib/publish/Licence.scala b/libs/javalib/src/mill/javalib/publish/Licence.scala index 0c2f007f29a6..2dc3d3e9e1a7 100644 --- a/libs/javalib/src/mill/javalib/publish/Licence.scala +++ b/libs/javalib/src/mill/javalib/publish/Licence.scala @@ -5,15 +5,393 @@ package mill.javalib.publish * in the companion object, e.g. [[License.MIT]], [[License.`Apache-2.0`]], etc. */ case class License( - id: String, + id: String = "", name: String, url: String, - isOsiApproved: Boolean, - isFsfLibre: Boolean, - distribution: String + isOsiApproved: Boolean = false, + isFsfLibre: Boolean = false, + distribution: String = "" ) object License { + // ujson.read(requests.get("https://raw.githubusercontent.com/spdx/license-list-data/master/json/licenses.json")) + // show(res0("licenses").arr.map(_("licenseId").str)) + private[mill] lazy val knownMap = known.map(l => l.id -> l).toMap + private lazy val known = Seq( + `0BSD`, + `AAL`, + `Abstyles`, + `Adobe-2006`, + `Adobe-Glyph`, + `ADSL`, + `AFL-1.1`, + `AFL-1.2`, + `AFL-2.0`, + `AFL-2.1`, + `AFL-3.0`, + `Afmparse`, + `AGPL-1.0`, + `AGPL-3.0-only`, + `AGPL-3.0-or-later`, + `Aladdin`, + `AMDPLPA`, + `AML`, + `AMPAS`, + `ANTLR-PD`, + `Apache-1.0`, + `Apache-1.1`, + `Apache-2.0`, + `APAFML`, + `APL-1.0`, + `APSL-1.0`, + `APSL-1.1`, + `APSL-1.2`, + `APSL-2.0`, + `Artistic-1.0-cl8`, + `Artistic-1.0-Perl`, + `Artistic-1.0`, + `Artistic-2.0`, + `Bahyph`, + `Barr`, + `Beerware`, + `BitTorrent-1.0`, + `BitTorrent-1.1`, + `Borceux`, + `BSD-1-Clause`, + `BSD-2-Clause-FreeBSD`, + `BSD-2-Clause-NetBSD`, + `BSD-2-Clause-Patent`, + `BSD-2-Clause`, + `BSD-3-Clause-Attribution`, + `BSD-3-Clause-Clear`, + `BSD-3-Clause-LBNL`, + `BSD-3-Clause-No-Nuclear-License-2014`, + `BSD-3-Clause-No-Nuclear-License`, + `BSD-3-Clause-No-Nuclear-Warranty`, + `BSD-3-Clause`, + `BSD-4-Clause-UC`, + `BSD-4-Clause`, + `BSD-Protection`, + `BSD-Source-Code`, + `BSL-1.0`, + `bzip2-1.0.5`, + `bzip2-1.0.6`, + `Caldera`, + `CATOSL-1.1`, + `CC-BY-1.0`, + `CC-BY-2.0`, + `CC-BY-2.5`, + `CC-BY-3.0`, + `CC-BY-4.0`, + `CC-BY-NC-1.0`, + `CC-BY-NC-2.0`, + `CC-BY-NC-2.5`, + `CC-BY-NC-3.0`, + `CC-BY-NC-4.0`, + `CC-BY-NC-ND-1.0`, + `CC-BY-NC-ND-2.0`, + `CC-BY-NC-ND-2.5`, + `CC-BY-NC-ND-3.0`, + `CC-BY-NC-ND-4.0`, + `CC-BY-NC-SA-1.0`, + `CC-BY-NC-SA-2.0`, + `CC-BY-NC-SA-2.5`, + `CC-BY-NC-SA-3.0`, + `CC-BY-NC-SA-4.0`, + `CC-BY-ND-1.0`, + `CC-BY-ND-2.0`, + `CC-BY-ND-2.5`, + `CC-BY-ND-3.0`, + `CC-BY-ND-4.0`, + `CC-BY-SA-1.0`, + `CC-BY-SA-2.0`, + `CC-BY-SA-2.5`, + `CC-BY-SA-3.0`, + `CC-BY-SA-4.0`, + `CC0-1.0`, + `CDDL-1.0`, + `CDDL-1.1`, + `CDLA-Permissive-1.0`, + `CDLA-Sharing-1.0`, + `CECILL-1.0`, + `CECILL-1.1`, + `CECILL-2.0`, + `CECILL-2.1`, + `CECILL-B`, + `CECILL-C`, + `ClArtistic`, + `CNRI-Jython`, + `CNRI-Python-GPL-Compatible`, + `CNRI-Python`, + `Condor-1.1`, + `CPAL-1.0`, + `CPL-1.0`, + `CPOL-1.02`, + `Crossword`, + `CrystalStacker`, + `CUA-OPL-1.0`, + `Cube`, + `curl`, + `D-FSL-1.0`, + `diffmark`, + `DOC`, + `Dotseqn`, + `DSDP`, + `dvipdfm`, + `ECL-1.0`, + `ECL-2.0`, + `EFL-1.0`, + `EFL-2.0`, + `eGenix`, + `Entessa`, + `EPL-1.0`, + `EPL-2.0`, + `ErlPL-1.1`, + `EUDatagrid`, + `EUPL-1.0`, + `EUPL-1.1`, + `EUPL-1.2`, + `Eurosym`, + `Fair`, + `Frameworx-1.0`, + `FreeImage`, + `FSFAP`, + `FSFUL`, + `FSFULLR`, + `FTL`, + `GFDL-1.1-only`, + `GFDL-1.1-or-later`, + `GFDL-1.2-only`, + `GFDL-1.2-or-later`, + `GFDL-1.3-only`, + `GFDL-1.3-or-later`, + `Giftware`, + `GL2PS`, + `Glide`, + `Glulxe`, + `gnuplot`, + `GPL-1.0-only`, + `GPL-1.0-or-later`, + `GPL-2.0-only`, + `GPL-2.0-or-later`, + `GPL-3.0-only`, + `GPL-3.0-or-later`, + `gSOAP-1.3b`, + `HaskellReport`, + `HPND`, + `IBM-pibs`, + `ICU`, + `IJG`, + `ImageMagick`, + `iMatix`, + `Imlib2`, + `Info-ZIP`, + `Intel-ACPI`, + `Intel`, + `Interbase-1.0`, + `IPA`, + `IPL-1.0`, + `ISC`, + `JasPer-2.0`, + `JSON`, + `LAL-1.2`, + `LAL-1.3`, + `Latex2e`, + `Leptonica`, + `LGPL-2.0-only`, + `LGPL-2.0-or-later`, + `LGPL-2.1-only`, + `LGPL-2.1-or-later`, + `LGPL-3.0-only`, + `LGPL-3.0-or-later`, + `LGPLLR`, + `Libpng`, + `libtiff`, + `LiLiQ-P-1.1`, + `LiLiQ-R-1.1`, + `LiLiQ-Rplus-1.1`, + `LPL-1.0`, + `LPL-1.02`, + `LPPL-1.0`, + `LPPL-1.1`, + `LPPL-1.2`, + `LPPL-1.3a`, + `LPPL-1.3c`, + `MakeIndex`, + `MirOS`, + `MIT-advertising`, + `MIT-CMU`, + `MIT-enna`, + `MIT-feh`, + `MIT`, + `MITNFA`, + `Motosoto`, + `mpich2`, + `MPL-1.0`, + `MPL-1.1`, + `MPL-2.0-no-copyleft-exception`, + `MPL-2.0`, + `MS-PL`, + `MS-RL`, + `MTLL`, + `Multics`, + `Mup`, + `NASA-1.3`, + `Naumen`, + `NBPL-1.0`, + `NCSA`, + `Net-SNMP`, + `NetCDF`, + `Newsletr`, + `NGPL`, + `NLOD-1.0`, + `NLPL`, + `Nokia`, + `NOSL`, + `Noweb`, + `NPL-1.0`, + `NPL-1.1`, + `NPOSL-3.0`, + `NRL`, + `NTP`, + `OCCT-PL`, + `OCLC-2.0`, + `ODbL-1.0`, + `OFL-1.0`, + `OFL-1.1`, + `OGTSL`, + `OLDAP-1.1`, + `OLDAP-1.2`, + `OLDAP-1.3`, + `OLDAP-1.4`, + `OLDAP-2.0.1`, + `OLDAP-2.0`, + `OLDAP-2.1`, + `OLDAP-2.2.1`, + `OLDAP-2.2.2`, + `OLDAP-2.2`, + `OLDAP-2.3`, + `OLDAP-2.4`, + `OLDAP-2.5`, + `OLDAP-2.6`, + `OLDAP-2.7`, + `OLDAP-2.8`, + `OML`, + `OpenSSL`, + `OPL-1.0`, + `OSET-PL-2.1`, + `OSL-1.0`, + `OSL-1.1`, + `OSL-2.0`, + `OSL-2.1`, + `OSL-3.0`, + `PDDL-1.0`, + `PHP-3.0`, + `PHP-3.01`, + `Plexus`, + `PostgreSQL`, + `psfrag`, + `psutils`, + `Python-2.0`, + `Qhull`, + `QPL-1.0`, + `Rdisc`, + `RHeCos-1.1`, + `RPL-1.1`, + `RPL-1.5`, + `RPSL-1.0`, + `RSA-MD`, + `RSCPL`, + `Ruby`, + `SAX-PD`, + `Saxpath`, + `SCEA`, + `Sendmail`, + `SGI-B-1.0`, + `SGI-B-1.1`, + `SGI-B-2.0`, + `SimPL-2.0`, + `SISSL-1.2`, + `SISSL`, + `Sleepycat`, + `SMLNJ`, + `SMPPL`, + `SNIA`, + `Spencer-86`, + `Spencer-94`, + `Spencer-99`, + `SPL-1.0`, + `SugarCRM-1.1.3`, + `SWL`, + `TCL`, + `TCP-wrappers`, + `TMate`, + `TORQUE-1.1`, + `TOSL`, + `Unicode-DFS-2015`, + `Unicode-DFS-2016`, + `Unicode-TOU`, + `Unlicense`, + `UPL-1.0`, + `Vim`, + `VOSTROM`, + `VSL-1.0`, + `W3C-19980720`, + `W3C-20150513`, + `W3C`, + `Watcom-1.0`, + `Wsuipa`, + `WTFPL`, + `X11`, + `Xerox`, + `XFree86-1.1`, + `xinetd`, + `Xnet`, + `xpp`, + `XSkat`, + `YPL-1.0`, + `YPL-1.1`, + `Zed`, + `Zend-2.0`, + `Zimbra-1.3`, + `Zimbra-1.4`, + `zlib-acknowledgement`, + `Zlib`, + `ZPL-1.1`, + `ZPL-2.0`, + `ZPL-2.1`, + `AGPL-3.0`, + `eCos-2.0`, + `GFDL-1.1`, + `GFDL-1.2`, + `GFDL-1.3`, + `GPL-1.0+`, + `GPL-1.0`, + `GPL-2.0+`, + `GPL-2.0-with-autoconf-exception`, + `GPL-2.0-with-bison-exception`, + `GPL-2.0-with-classpath-exception`, + `GPL-2.0-with-font-exception`, + `GPL-2.0-with-GCC-exception`, + `GPL-2.0`, + `GPL-3.0+`, + `GPL-3.0-with-autoconf-exception`, + `GPL-3.0-with-GCC-exception`, + `GPL-3.0`, + `LGPL-2.0+`, + `LGPL-2.0`, + `LGPL-2.1+`, + `LGPL-2.1`, + `LGPL-3.0+`, + `LGPL-3.0`, + `Nunit`, + `StandardML-NJ`, + `wxWindows`, + // Misc + PublicDomain, + Scala, + TypesafeSubscriptionAgreement + ) /* wget https://raw.githubusercontent.com/spdx/license-list-data/master/json/licenses.json @@ -613,7 +991,7 @@ object License { isOsiApproved: Boolean, isFsfLibre: Boolean ): License = - License(fullName, id, s"https://spdx.org/licenses/$id.html", isOsiApproved, isFsfLibre, "repo") + License(id, fullName, s"https://spdx.org/licenses/$id.html", isOsiApproved, isFsfLibre, "repo") val PublicDomain: License = License( id = "Public Domain", diff --git a/libs/javalib/src/mill/javalib/publish/Pom.scala b/libs/javalib/src/mill/javalib/publish/Pom.scala index 2651ae320e2c..ea28c6975f74 100644 --- a/libs/javalib/src/mill/javalib/publish/Pom.scala +++ b/libs/javalib/src/mill/javalib/publish/Pom.scala @@ -143,6 +143,7 @@ object Pom { {d.id} {d.name} {d.url} + {d.email} {{d.organization}.optional} {{d.organizationUrl}.optional} diff --git a/libs/javalib/src/mill/javalib/publish/model.scala b/libs/javalib/src/mill/javalib/publish/model.scala index df4f8706bce6..30bf19401ed1 100644 --- a/libs/javalib/src/mill/javalib/publish/model.scala +++ b/libs/javalib/src/mill/javalib/publish/model.scala @@ -60,11 +60,12 @@ case class Dependency( ) derives RW case class Developer( - id: String, + id: String = "", name: String, - url: String, + url: String = "", organization: Option[String] = None, - organizationUrl: Option[String] = None + organizationUrl: Option[String] = None, + @com.lihaoyi.unroll email: String = "" ) derives RW case class PomSettings( diff --git a/libs/tabcomplete/test/src/mill/tabcomplete/TabCompleteTests.scala b/libs/tabcomplete/test/src/mill/tabcomplete/TabCompleteTests.scala index 85a9bed79363..198972fe7d89 100644 --- a/libs/tabcomplete/test/src/mill/tabcomplete/TabCompleteTests.scala +++ b/libs/tabcomplete/test/src/mill/tabcomplete/TabCompleteTests.scala @@ -171,6 +171,7 @@ object TabCompleteTests extends TestSuite { Set( "-b Ring the bell once if the run completes successfully, twice if it fails.", "-w Watch and re-run the given tasks when when their inputs change.", + "-f Select the build.mill file or Java/Scala/Kotlin script file to run", "-k Continue build, even after build failures.", "-D Define (or overwrite) a system property.", "-d Show debug output on STDOUT", @@ -204,7 +205,6 @@ object TabCompleteTests extends TestSuite { assertGoldenLiteral( evalComplete("1", "./mill", "--"), Set( - "--bsp Enable BSP server mode.", "--debug Show debug output on STDOUT", "--bell Ring the bell once if the run completes successfully, twice if it fails.", "--interactive Run Mill in interactive mode, suitable for opening REPLs and taking user input. Identical to --no-daemon. Must be the first argument.", @@ -216,6 +216,8 @@ object TabCompleteTests extends TestSuite { "--watch Watch and re-run the given tasks when when their inputs change.", "--no-wait-for-build-lock Do not wait for an exclusive lock on the Mill output directory to evaluate tasks / commands.", "--help-advanced Print a internal or advanced command flags not intended for common usage", + "--bsp Enable BSP server mode.", + "--file Select the build.mill file or Java/Scala/Kotlin script file to run", "--offline Try to work offline. This tells modules that support it to work offline and avoid any access to the internet. This is on a best effort basis. There are currently no guarantees that modules don't attempt to fetch remote sources.", "--keep-going Continue build, even after build failures.", "--define Define (or overwrite) a system property.", diff --git a/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala b/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala index a48d1083820f..1b5075c7b6fa 100644 --- a/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala +++ b/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala @@ -8,12 +8,12 @@ import mill.api.daemon.internal.{ PathRefApi, RootModuleApi } -import mill.api.{Logger, Result, SystemStreams, Val} +import mill.api.{BuildCtx, Discover, Logger, PathRef, Result, SelectMode, SystemStreams, Val} import mill.constants.CodeGenConstants.* import mill.constants.OutFiles.{millBuild, millRunnerState} import mill.api.daemon.Watchable import mill.api.internal.RootModule -import mill.api.{BuildCtx, PathRef, SelectMode} +import mill.constants.OutFiles import mill.internal.PrefixLogger import mill.meta.{FileImportGraph, MillBuildRootModule} import mill.meta.CliImports @@ -44,12 +44,12 @@ import scala.collection.mutable.Buffer */ class MillBuildBootstrap( projectRoot: os.Path, - output: os.Path, + output0: os.Path, keepGoing: Boolean, imports: Seq[String], env: Map[String, String], ec: Option[ThreadPoolExecutor], - tasksAndParams: Seq[String], + tasksAndParams0: Seq[String], prevRunnerState: RunnerState, logger: Logger, needBuildFile: Boolean, @@ -59,10 +59,24 @@ class MillBuildBootstrap( streams0: SystemStreams, selectiveExecution: Boolean, offline: Boolean, - reporter: EvaluatorApi => Int => Option[CompileProblemReporter] + reporter: EvaluatorApi => Int => Option[CompileProblemReporter], + millFileOpt0: Option[os.Path], + skipSelectiveExecution: Boolean ) { outer => + val (tasksAndParams, millFileOpt) = (tasksAndParams0, millFileOpt0) match { + case (Seq(head, rest*), None) + if head.endsWith(".java") || head.endsWith(".scala") || head.endsWith(".kt") => + (Seq("run") ++ rest, Some(os.Path(head, projectRoot))) + case _ => (tasksAndParams0, millFileOpt0) + } import MillBuildBootstrap.* + val output = millFileOpt match { + case Some(millFile) => output0 / millFile.relativeTo(projectRoot).segments + case None => output0 + } + + if (skipSelectiveExecution) os.remove(output / OutFiles.millSelectiveExecution) val millBootClasspath: Seq[os.Path] = prepareMillBootClasspath(output) val millBootClasspathPathRefs: Seq[PathRef] = millBootClasspath.map(PathRef(_, quick = true)) @@ -97,49 +111,71 @@ class MillBuildBootstrap( os.exists(currentRoot / rootBuildFileName) ) - val (nestedState, headerDataOpt) = - if (depth == 0) { - // On this level we typically want to assume a Mill project, which means we want to require an existing `build.mill`. - // Unfortunately, some tasks also make sense without a `build.mill`, e.g. the `init` command. - // Hence, we only report a missing `build.mill` as a problem if the command itself does not succeed. - lazy val state = evaluateRec(depth + 1) - if (currentRootContainsBuildFile) (state, None) - else { - val msg = - s"No build file (${rootBuildFileNames.asScala.mkString(", ")}) found in $projectRoot. Are you in a Mill project directory?" - val res = - if (needBuildFile) RunnerState(None, Nil, Some(msg), None) - else { - state match { - case RunnerState(bootstrapModuleOpt, frames, Some(error), None) => - // Add a potential clue (missing build.mill) to the underlying error message - RunnerState(bootstrapModuleOpt, frames, Some(msg + "\n" + error)) - case state => state - } + val (nestedState, headerDataOpt) = millFileOpt match { + case Some(millFile) => + import mill.* + implicit val rootModuleInfo: RootModule.Info = + new RootModule.Info(projectRoot, output, projectRoot) + + val bootstrapModule = millFile.ext match { + case "java" => new mill.meta.ScriptModule.Java(millFile) { + override lazy val millDiscover = Discover[this.type] + } + case "scala" => new mill.meta.ScriptModule.Scala(millFile) { + override lazy val millDiscover = Discover[this.type] + } + case "kt" => new mill.meta.ScriptModule.Kotlin(millFile) { + override lazy val millDiscover = Discover[this.type] } - (res, None) } - } else { - val parsedScriptFiles = FileImportGraph - .parseBuildFiles( - projectRoot, - currentRoot / os.up, - output, - MillScalaParser.current.value - ) - - val state = - if (currentRootContainsBuildFile) evaluateRec(depth + 1) + val yamlHeader = mill.constants.Util.readBuildHeader(millFile.toNIO, millFile.last, true) + + (RunnerState(Some(bootstrapModule), Nil, None, Some(millFile.last)), Some(yamlHeader)) + case None => + if (depth == 0) { + // On this level we typically want to assume a Mill project, which means we want to require an existing `build.mill`. + // Unfortunately, some tasks also make sense without a `build.mill`, e.g. the `init` command. + // Hence, we only report a missing `build.mill` as a problem if the command itself does not succeed. + lazy val state = evaluateRec(depth + 1) + if (currentRootContainsBuildFile) (state, None) else { - val bootstrapModule = - new MillBuildRootModule.BootstrapModule()( - using new RootModule.Info(currentRoot, output, projectRoot) - ) - RunnerState(Some(bootstrapModule), Nil, None, Some(parsedScriptFiles.buildFile)) + val msg = + s"No build file (${rootBuildFileNames.asScala.mkString(", ")}) found in $projectRoot. Are you in a Mill project directory?" + val res = + if (needBuildFile) RunnerState(None, Nil, Some(msg), None) + else { + state match { + case RunnerState(bootstrapModuleOpt, frames, Some(error), None) => + // Add a potential clue (missing build.mill) to the underlying error message + RunnerState(bootstrapModuleOpt, frames, Some(msg + "\n" + error)) + case state => state + } + } + (res, None) } + } else { + val parsedScriptFiles = FileImportGraph + .parseBuildFiles( + projectRoot, + currentRoot / os.up, + output, + MillScalaParser.current.value + ) - (state, Some(parsedScriptFiles.headerData)) - } + val state = + if (currentRootContainsBuildFile) evaluateRec(depth + 1) + else { + val bootstrapModule = + new MillBuildRootModule.BootstrapModule()( + using new RootModule.Info(currentRoot, output, projectRoot) + ) + RunnerState(Some(bootstrapModule), Nil, None, Some(parsedScriptFiles.buildFile)) + } + + (state, Some(parsedScriptFiles.headerData)) + } + + } val classloaderChanged = prevRunnerState.frames.lift(depth + 1).flatMap(_.classLoaderOpt) != @@ -186,44 +222,33 @@ class MillBuildBootstrap( rootModuleRes match { case Result.Failure(err) => nestedState.add(errorOpt = Some(err)) - case Result.Success((buildFileApi)) => - - Using.resource(makeEvaluator( - projectRoot, - output, - keepGoing, - env, - logger, - ec, - allowPositionalCommandArgs, - systemExit, - streams0, - selectiveExecution, - offline, - newWorkerCache, - nestedState.frames.headOption.map(_.codeSignatures).getOrElse(Map.empty), - buildFileApi.rootModule, - // We want to use the grandparent buildHash, rather than the parent - // buildHash, because the parent build changes are instead detected - // by analyzing the scriptImportGraph in a more fine-grained manner. - nestedState - .frames - .dropRight(1) - .headOption - .map(_.runClasspath) - .getOrElse(millBootClasspathPathRefs) - .map(p => (os.Path(p.javaPath), p.sig)) - .hashCode(), - nestedState - .frames - .headOption - .flatMap(_.classLoaderOpt) - .map(_.hashCode()) - .getOrElse(0), - depth, - actualBuildFileName = nestedState.buildFile, - headerData = headerDataOpt.getOrElse("") - )) { evaluator => + case Result.Success(buildFileApi) => + + Using.resource( + makeEvaluator( + depth, + output, + nestedState.frames.headOption.map(_.codeSignatures).getOrElse(Map.empty), + headerDataOpt, + newWorkerCache, + buildFileApi, + nestedState + .frames + .dropRight(1) + .headOption + .map(_.runClasspath) + .getOrElse(millBootClasspathPathRefs) + .map(p => (os.Path(p.javaPath), p.sig)) + .hashCode(), + nestedState + .frames + .headOption + .flatMap(_.classLoaderOpt) + .map(_.hashCode()) + .getOrElse(0), + actualBuildFileName = nestedState.buildFile + ) + ) { evaluator => if (depth == requestedDepth) { processFinalTasks(nestedState, buildFileApi, evaluator) } else if (depth <= requestedDepth) nestedState @@ -245,6 +270,43 @@ class MillBuildBootstrap( } } + private def makeEvaluator( + depth: Int, + outputPath: os.Path, + codeSignatures: Map[String, Int], + headerDataOpt: Option[String], + newWorkerCache: Map[String, (Int, Val)], + buildFileApi: BuildFileApi, + millClassloaderSigHash: Int, + millClassloaderIdentityHash: Int, + actualBuildFileName: Option[String] + ) = { + MillBuildBootstrap.makeEvaluator( + projectRoot, + outputPath, + keepGoing, + env, + logger, + ec, + allowPositionalCommandArgs, + systemExit, + streams0, + selectiveExecution, + offline, + newWorkerCache, + codeSignatures, + buildFileApi.rootModule, + // We want to use the grandparent buildHash, rather than the parent + // buildHash, because the parent build changes are instead detected + // by analyzing the scriptImportGraph in a more fine-grained manner. + millClassloaderSigHash, + millClassloaderIdentityHash, + depth, + actualBuildFileName = actualBuildFileName, + headerData = headerDataOpt.getOrElse("") + ) + } + /** * Handles the compilation of `build.mill` or one of the meta-builds. These * cases all only need us to run evaluate `runClasspath` and @@ -359,7 +421,7 @@ class MillBuildBootstrap( assert(nestedState.frames.forall(_.evaluator.isDefined)) - val (evaled, evalWatched, moduleWatches) = evaluateWithWatches( + val (evaled, evalWatched, moduleWatched) = evaluateWithWatches( buildFileApi, evaluator, tasksAndParams, @@ -369,7 +431,7 @@ class MillBuildBootstrap( val evalState = RunnerState.Frame( evaluator.workerCache.toMap, evalWatched, - moduleWatches, + moduleWatched, Map.empty, None, Nil, diff --git a/runner/daemon/src/mill/daemon/MillMain0.scala b/runner/daemon/src/mill/daemon/MillMain0.scala index 9691b35c7e32..6a5d8ccf23a9 100644 --- a/runner/daemon/src/mill/daemon/MillMain0.scala +++ b/runner/daemon/src/mill/daemon/MillMain0.scala @@ -237,7 +237,7 @@ object MillMain0 { val out = os.Path(OutFiles.outFor(outMode), BuildCtx.workspaceRoot) Using.resources(new TailManager(daemonDir), createEc()) { (tailManager, ec) => def runMillBootstrap( - enterKeyPressed: Boolean, + skipSelectiveExecution: Boolean, prevState: Option[RunnerState], tasksAndParams: Seq[String], streams: SystemStreams, @@ -257,7 +257,7 @@ object MillMain0 { def proceed(logger: Logger): Watching.Result[RunnerState] = { // Enter key pressed, removing mill-selective-execution.json to // ensure all tasks re-run even though no inputs may have changed - if (enterKeyPressed) os.remove(out / OutFiles.millSelectiveExecution) + mill.api.SystemStreamsUtils.withStreams(logger.streams) { mill.api.FilesystemCheckerEnabled.withValue( !config.noFilesystemChecker.value @@ -265,24 +265,26 @@ object MillMain0 { tailManager.withOutErr(logger.streams.out, logger.streams.err) { new MillBuildBootstrap( projectRoot = BuildCtx.workspaceRoot, - output = out, + output0 = out, // In BSP server, we want to evaluate as many tasks as possible, // in order to give as many results as available in BSP responses keepGoing = bspMode || config.keepGoing.value, imports = config.imports, env = env ++ extraEnv, ec = ec, - tasksAndParams = tasksAndParams, + tasksAndParams0 = tasksAndParams, prevRunnerState = prevState.getOrElse(stateCache), logger = logger, needBuildFile = needBuildFile(config), requestedMetaLevel = config.metaLevel, - config.allowPositional.value, + allowPositionalCommandArgs = config.allowPositional.value, systemExit = systemExit, streams0 = streams, selectiveExecution = config.watch.value, offline = config.offline.value, - reporter = reporter + reporter = reporter, + millFileOpt0 = config.file, + skipSelectiveExecution = skipSelectiveExecution ).evaluate() } } @@ -312,7 +314,7 @@ object MillMain0 { if (config.tabComplete.value) { val bootstrapped = runMillBootstrap( - enterKeyPressed = false, + skipSelectiveExecution = false, Some(stateCache), Seq( "mill.tabcomplete.TabCompleteModule/complete" @@ -440,11 +442,6 @@ object MillMain0 { ).run() (true, RunnerState(None, Nil, None)) } else { - // When starting a --watch, clear the `mill-selective-execution.json` - // file, so that the first run always selects everything and only - // subsequent re-runs are selective depending on what changed. - if (config.watch.value) - os.remove(out / OutFiles.millSelectiveExecution) Watching.watchLoop( ringBell = config.ringBell.value, watch = Option.when(config.watch.value)(Watching.WatchArgs( @@ -454,16 +451,17 @@ object MillMain0 { daemonDir = daemonDir )), streams = streams, - evaluate = (enterKeyPressed: Boolean, prevState: Option[RunnerState]) => { - adjustJvmProperties(userSpecifiedProperties, initialSystemProperties) - runMillBootstrap( - enterKeyPressed, - prevState, - config.leftoverArgs.value, - streams, - config.leftoverArgs.value.mkString(" ") - ) - } + evaluate = + (skipSelectiveExecution: Boolean, prevState: Option[RunnerState]) => { + adjustJvmProperties(userSpecifiedProperties, initialSystemProperties) + runMillBootstrap( + skipSelectiveExecution, + prevState, + config.leftoverArgs.value, + streams, + config.leftoverArgs.value.mkString(" ") + ) + } ) } } diff --git a/runner/daemon/src/mill/daemon/Watching.scala b/runner/daemon/src/mill/daemon/Watching.scala index 49c24c382ee9..156c1b5d6f5f 100644 --- a/runner/daemon/src/mill/daemon/Watching.scala +++ b/runner/daemon/src/mill/daemon/Watching.scala @@ -18,7 +18,7 @@ object Watching { case class Result[T](watched: Seq[Watchable], error: Option[String], result: T) trait Evaluate[T] { - def apply(enterKeyPressed: Boolean, previousState: Option[T]): Result[T] + def apply(skipSelectiveExecution: Boolean, previousState: Option[T]): Result[T] } /** @@ -61,23 +61,23 @@ object Watching { watch match { case None => val Result(_, errorOpt, result) = - evaluate(enterKeyPressed = false, previousState = None) + evaluate(skipSelectiveExecution = false, previousState = None) handleError(errorOpt) (errorOpt.isEmpty, result) case Some(watchArgs) => var prevState: Option[T] = None - var enterKeyPressed = false + var skipSelectiveExecution = true // Always skip selective execution for first run // Exits when the thread gets interruped. while (true) { - val Result(watchables, errorOpt, result) = evaluate(enterKeyPressed, prevState) + val Result(watchables, errorOpt, result) = evaluate(skipSelectiveExecution, prevState) prevState = Some(result) handleError(errorOpt) try { watchArgs.setIdle(true) - enterKeyPressed = watchAndWait( + skipSelectiveExecution = watchAndWait( watchables, watchArgs, () => Option.when(lookForEnterKey(streams.in))(()), diff --git a/runner/meta/package.mill b/runner/meta/package.mill index ef93249492f6..744b6220056e 100644 --- a/runner/meta/package.mill +++ b/runner/meta/package.mill @@ -8,7 +8,8 @@ object `package` extends MillPublishScalaModule with BuildInfo { def moduleDeps = Seq( build.runner.codesig, build.libs.util, - build.libs.scalalib + build.libs.scalalib, + build.libs.kotlinlib ) def buildInfoPackageName = "mill.meta" diff --git a/runner/meta/src/mill/meta/ScriptModule.scala b/runner/meta/src/mill/meta/ScriptModule.scala new file mode 100644 index 000000000000..ebe79a097cf3 --- /dev/null +++ b/runner/meta/src/mill/meta/ScriptModule.scala @@ -0,0 +1,37 @@ +package mill.meta +import mill.* +import mill.javalib.publish._ +import mill.api.Discover +import mill.util.MainRootModule + +trait ScriptModule extends MainRootModule with mill.javalib.JavaModule + with mill.javalib.NativeImageModule + with mill.javalib.PublishModule { + def millFile: os.Path + override def allSourceFiles = Task.Sources(millFile) + def pomSettings = PomSettings( + description = "", + organization = "", + url = "", + licenses = Seq(), + versionControl = VersionControl(), + developers = Seq() + ) + def publishVersion = Task { "0.0.1" } +} +object ScriptModule { + trait Java(val millFile: os.Path) extends ScriptModule { + override lazy val millDiscover = Discover[this.type] + + } + trait Scala(val millFile: os.Path) extends ScriptModule with mill.scalalib.ScalaModule { + def scalaVersion = mill.util.BuildInfo.scalaVersion + override def allSourceFiles = Task.Sources(millFile) + override lazy val millDiscover = Discover[this.type] + } + trait Kotlin(val millFile: os.Path) extends ScriptModule with mill.kotlinlib.KotlinModule { + def kotlinVersion = "1.9.24" + override def allSourceFiles = Task.Sources(millFile) + override lazy val millDiscover = Discover[this.type] + } +} diff --git a/test/Foo.java b/test/Foo.java new file mode 100644 index 000000000000..4aac95145253 --- /dev/null +++ b/test/Foo.java @@ -0,0 +1,35 @@ +//| mvnDeps: +//| - net.sourceforge.argparse4j:argparse4j:0.9.0 +//| - org.thymeleaf:thymeleaf:3.1.1.RELEASE +import net.sourceforge.argparse4j.ArgumentParsers; +import net.sourceforge.argparse4j.inf.ArgumentParser; +import net.sourceforge.argparse4j.inf.Namespace; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +public class Foo { + public static String generateHtml(String text) { + Context context = new Context(); + context.setVariable("text", text); + return new TemplateEngine().process("

", context); + } + + public static void main(String[] args) { + ArgumentParser parser = ArgumentParsers.newFor("template") + .build() + .defaultHelp(true) + .description("Inserts text into a HTML template"); + + parser.addArgument("-t", "--text").required(true).help("text to insert"); + + Namespace ns = null; + try { + ns = parser.parseArgs(args); + } catch (Exception e) { + System.out.println(e.getMessage()); + System.exit(1); + } + + System.out.println(generateHtml(ns.getString("text"))); + } +} diff --git a/website/docs/modules/ROOT/pages/cli/build-header.adoc b/website/docs/modules/ROOT/pages/cli/build-header.adoc index 38beb0cceb04..83bfc69e61a6 100644 --- a/website/docs/modules/ROOT/pages/cli/build-header.adoc +++ b/website/docs/modules/ROOT/pages/cli/build-header.adoc @@ -137,4 +137,11 @@ Missing environment variables are converted to the empty string. == Meta-build Task Overrides -include::partial$example/cli/header/1-tasks.adoc[] \ No newline at end of file +include::partial$example/cli/header/1-tasks.adoc[] + +== Single-File Project Build Headers + +Build Header configuration is also used for +xref:javalib/module-config.adoc#_configuring_single_file_projects[Configuring Single-File Projects], +as a lightweight syntax for embedding configuration values within the single Java, Scala, or Kotlin +file. \ No newline at end of file diff --git a/website/docs/modules/ROOT/pages/index.adoc b/website/docs/modules/ROOT/pages/index.adoc index 119a95fd4a82..13a4ab19c994 100644 --- a/website/docs/modules/ROOT/pages/index.adoc +++ b/website/docs/modules/ROOT/pages/index.adoc @@ -9,9 +9,9 @@ in the JVM ecosystem: * Mill builds the same Java project xref:comparisons/why-mill.adoc#_performance[3-6x faster than Maven or Gradle] due to aggressive caching & parallelism -* Mill's rich featureset means -xref:comparisons/why-mill.adoc#_rich_builtins[less fiddling with plugins], -since everything needed for development is built in +* Mill's featureset supports everything from xref:javalib/intro.adoc#_single_file_projects[single-files] to +xref:large/large.adoc[large projects] needing +xref:comparisons/why-mill.adoc#_rich_builtins[less fiddling with plugins] * Mill builds are xref:comparisons/why-mill.adoc#_ide_support[easily explorable in your IDE], letting you work on them without constantly googling for help diff --git a/website/docs/modules/ROOT/pages/javalib/intro.adoc b/website/docs/modules/ROOT/pages/javalib/intro.adoc index d4fdecdd3a94..6ac15246f204 100644 --- a/website/docs/modules/ROOT/pages/javalib/intro.adoc +++ b/website/docs/modules/ROOT/pages/javalib/intro.adoc @@ -3,9 +3,15 @@ :page-aliases: Intro_to_Mill.adoc, Intro_to_Mill_for_Java.adoc, Java_Intro_to_Mill.adoc :language: Java :language-small: java +:language-ext: java include::partial$Intro_Header.adoc[] + +== Single-File Projects + +include::partial$example/javalib/basic/5-single-file.adoc[] + == Simple Java Module include::partial$example/javalib/basic/1-simple.adoc[] diff --git a/website/docs/modules/ROOT/pages/javalib/module-config.adoc b/website/docs/modules/ROOT/pages/javalib/module-config.adoc index dfba30ed2129..32c2ce3b0936 100644 --- a/website/docs/modules/ROOT/pages/javalib/module-config.adoc +++ b/website/docs/modules/ROOT/pages/javalib/module-config.adoc @@ -11,21 +11,36 @@ Many of the APIs covered here are listed in the API documentation: * {mill-doc-url}/api/latest/mill/javalib/JavaModule.html[mill.javalib.JavaModule] +== Configuring Single-File Projects + +include::partial$example/javalib/module/1-single-file.adoc[] + + == Common Configuration Overrides -include::partial$example/javalib/module/1-common-config.adoc[] +include::partial$example/javalib/module/2-common-config.adoc[] + + +== Custom Tasks + +include::partial$example/javalib/module/3-custom-tasks.adoc[] + + + +== Generated Sources + +include::partial$example/javalib/module/4-generated-sources.adoc[] + -[#_compilation_execution_flags] == Compilation & Execution Flags -include::partial$example/javalib/module/4-compilation-execution-flags.adoc[] +include::partial$example/javalib/module/5-compilation-execution-flags.adoc[] == Classpath and Filesystem Resources include::partial$example/javalib/module/7-resources.adoc[] -[#_annotation_processors] == Annotation Processors include::partial$example/javalib/module/8-annotation-processors.adoc[] @@ -34,21 +49,11 @@ include::partial$example/javalib/module/8-annotation-processors.adoc[] include::partial$example/javalib/module/9-docjar.adoc[] -[[specifying-main-class]] == Specifying the Main Class include::partial$example/javalib/module/11-main-class.adoc[] -== Generated Sources - -include::partial$example/javalib/module/3-generated-sources.adoc[] - -== Custom Tasks - -include::partial$example/javalib/module/2-custom-tasks.adoc[] - -[#_native_c_code_with_jni] == Native C Code with JNI include::partial$example/javalib/module/15-jni.adoc[] diff --git a/website/docs/modules/ROOT/pages/kotlinlib/intro.adoc b/website/docs/modules/ROOT/pages/kotlinlib/intro.adoc index e05cf45a17ee..dc39a900f419 100644 --- a/website/docs/modules/ROOT/pages/kotlinlib/intro.adoc +++ b/website/docs/modules/ROOT/pages/kotlinlib/intro.adoc @@ -3,6 +3,7 @@ :page-aliases: Kotlin_Intro_to_Mill.adoc :language: Kotlin :language-small: kotlin +:language-ext: kt include::partial$Intro_Header.adoc[] @@ -11,6 +12,10 @@ still under active development. It is expected to continue evolving over time as Android and Multiplatform support is fleshed out. Try it out, but please be aware of its limitations! +== Single-File Projects + +include::partial$example/kotlinlib/basic/5-single-file.adoc[] + == Simple Kotlin Module include::partial$example/kotlinlib/basic/1-simple.adoc[] diff --git a/website/docs/modules/ROOT/pages/kotlinlib/module-config.adoc b/website/docs/modules/ROOT/pages/kotlinlib/module-config.adoc index c09db8e6a357..de5b838f4b26 100644 --- a/website/docs/modules/ROOT/pages/kotlinlib/module-config.adoc +++ b/website/docs/modules/ROOT/pages/kotlinlib/module-config.adoc @@ -13,14 +13,30 @@ Many of the APIs covered here are listed in the API documentation: +== Configuring Single-File Projects + +include::partial$example/kotlinlib/module/1-single-file.adoc[] + + == Common Configuration Overrides -include::partial$example/kotlinlib/module/1-common-config.adoc[] +include::partial$example/kotlinlib/module/2-common-config.adoc[] + + +== Custom Tasks + +include::partial$example/kotlinlib/module/3-custom-tasks.adoc[] + + +== Generated Sources + +include::partial$example/kotlinlib/module/4-generated-sources.adoc[] + == Compilation & Execution Flags -include::partial$example/kotlinlib/module/4-compilation-execution-flags.adoc[] +include::partial$example/kotlinlib/module/5-compilation-execution-flags.adoc[] == Classpath and Filesystem Resources @@ -34,18 +50,14 @@ include::partial$example/kotlinlib/module/8-kotlin-compiler-plugins.adoc[] include::partial$example/kotlinlib/module/9-docjar.adoc[] -== Specifying the Main Class - -include::partial$example/kotlinlib/module/11-main-class.adoc[] - +== Dependency Injection with Dagger and KSP -== Generated Sources +include::partial$example/kotlinlib/module/10-dependency-injection.adoc[] -include::partial$example/kotlinlib/module/3-generated-sources.adoc[] +== Specifying the Main Class -== Custom Tasks +include::partial$example/kotlinlib/module/11-main-class.adoc[] -include::partial$example/kotlinlib/module/2-custom-tasks.adoc[] == Native C Code with JNI diff --git a/website/docs/modules/ROOT/pages/scalalib/intro.adoc b/website/docs/modules/ROOT/pages/scalalib/intro.adoc index 38a4560fbf64..b64a665b28f6 100644 --- a/website/docs/modules/ROOT/pages/scalalib/intro.adoc +++ b/website/docs/modules/ROOT/pages/scalalib/intro.adoc @@ -3,9 +3,14 @@ :page-aliases: Intro_to_Mill_for_Scala.adoc, Scala_Intro_to_Mill.adoc :language: Scala :language-small: scala +:language-ext: scala include::partial$Intro_Header.adoc[] +== Single-File Projects + +include::partial$example/scalalib/basic/5-single-file.adoc[] + == Simple Scala Module include::partial$example/scalalib/basic/1-simple.adoc[] @@ -18,7 +23,6 @@ include::partial$example/scalalib/basic/2-custom-build-logic.adoc[] include::partial$example/scalalib/basic/3-multi-module.adoc[] - == `sbt`-Compatible Modules include::partial$example/scalalib/basic/4-compat-modules.adoc[] diff --git a/website/docs/modules/ROOT/pages/scalalib/module-config.adoc b/website/docs/modules/ROOT/pages/scalalib/module-config.adoc index ba8f5bddc2ae..52474db41be5 100644 --- a/website/docs/modules/ROOT/pages/scalalib/module-config.adoc +++ b/website/docs/modules/ROOT/pages/scalalib/module-config.adoc @@ -12,13 +12,26 @@ Many of the APIs covered here are listed in the Scaladoc: * {mill-doc-url}/api/latest/mill/scalalib/ScalaModule.html[mill.scalalib.ScalaModule] +== Configuring Single-File Projects + +include::partial$example/scalalib/module/1-single-file.adoc[] + + == Common Configuration Overrides -include::partial$example/scalalib/module/1-common-config.adoc[] +include::partial$example/scalalib/module/2-common-config.adoc[] + +== Custom Tasks + +include::partial$example/scalalib/module/3-custom-tasks.adoc[] + +== Generated Sources + +include::partial$example/scalalib/module/4-generated-sources.adoc[] == Compilation & Execution Flags -include::partial$example/scalalib/module/4-compilation-execution-flags.adoc[] +include::partial$example/scalalib/module/5-compilation-execution-flags.adoc[] == Classpath and Filesystem Resources @@ -45,15 +58,6 @@ include::partial$example/scalalib/module/14-cross-scala-version.adoc[] include::partial$example/scalalib/module/15-unidoc.adoc[] -== Generated Sources - -include::partial$example/scalalib/module/3-generated-sources.adoc[] - -== Custom Tasks - -include::partial$example/scalalib/module/2-custom-tasks.adoc[] - - == Using the Ammonite Repl / Scala console