diff --git a/.github/workflows/job.build.yml b/.github/workflows/job.build.yml index 36ce125..1622ada 100644 --- a/.github/workflows/job.build.yml +++ b/.github/workflows/job.build.yml @@ -46,12 +46,18 @@ jobs: with: channel: nightly - name: "Build: Java Compiler" - run: ./mvnw clean install -pl plexus-compilers + run: ./mvnw clean install -pl java-compiler - name: "Build: Kotlin Plugin" run: ./mvnw clean install -pl kotlin-plugin + - name: "Build: Elide Plugin" + run: ./mvnw clean install -pl elide-plugin - name: "Test: Java Compiler" - run: ./mvnw clean package -pl sample-java + run: ./mvnw test -pl java-compiler + - name: "Test: Java Compiler (Build Sample)" + run: ./mvnw clean package exec:java -f sample-java - name: "Test: Kotlin Plugin" - run: ./mvnw clean package -pl sample-kotlin - - name: "Test: Mixed source" - run: ./mvnw clean package -pl sample-mixed + run: ./mvnw test -pl kotlin-plugin + - name: "Test: Kotlin Plugin (Build Sample)" + run: ./mvnw clean package exec:java -f sample-kotlin + - name: "Test: Elide Plugin (Build Sample)" + run: ./mvnw clean package exec:java -f sample-mixed diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c843b7e --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +all: clean all-java all-kotlin all-plugin + +clean: + ./mvnw clean + +all-java: build-java test-java install-java sample-java + +all-kotlin: build-kotlin test-kotlin install-kotlin sample-kotlin + +all-plugin: build-plugin test-plugin install-plugin sample-plugin + +build-java: + ./mvnw compile -pl java-compiler + +build-kotlin: + ./mvnw compile -pl kotlin-plugin + +build-plugin: + ./mvnw compile -pl elide-plugin + +test-java: + ./mvnw test -pl java-compiler + +test-kotlin: + ./mvnw test -pl kotlin-plugin + +test-plugin: + ./mvnw test -pl elide-plugin + +install-java: + ./mvnw install -pl java-compiler + +install-kotlin: + ./mvnw install -pl kotlin-plugin + +install-plugin: + ./mvnw install -pl elide-plugin + +sample-java: + ./mvnw clean package exec:java -f sample-java + +sample-kotlin: + ./mvnw clean package exec:java -f sample-kotlin + +sample-plugin: + ./mvnw clean package exec:java -f sample-mixed \ No newline at end of file diff --git a/README.md b/README.md index 92b53eb..24559a1 100644 --- a/README.md +++ b/README.md @@ -11,69 +11,46 @@ This plugin can be consumed in a Maven project to use [Elide](https://elide.dev) - [x] Supports explicit path to `elide` - [x] Resolve `elide` via the `PATH` - [x] Swap out `kotlinc ...` for `elide kotlinc -- ...` -- [ ] Usability of Elide as a Maven toolchain +- [x] Usability of Elide as a Maven toolchain ## Usage -### Java +### Elide Plugin -Configuring Elide as your `javac` compiler: +The easiest way to start using Elide in your project is the `elide-maven-plugin`. Enable it and set `extensions` to +`true` and all of your Java and Kotlin sources will be compiled with Elide `javac` and `kotlinc`. **`pom.xml`** ```xml - maven-compiler-plugin - 3.15.0 - - - dev.elide - elide-plexus-compilers - 1.0.0 - - - - elide - + dev.elide + elide-maven-plugin + 1.0.0 + true ``` > [!TIP] -> See the [Java sample project](sample-java) for a usage example. Elide also provides -> a [Gradle plugin](https://github.com/elide-dev/gradle). +> See the [Mixed sources sample project](sample-mixed) for a usage example. -### Kotlin +### Kotlin drop-in replacement -Configuring the Elide Kotlin plugin is done the exact same way as configuring the Kotlin Maven plugin, just replacing -the plugin coordinates: +If you already have a project that uses the `kotlin-maven-plugin`, you can use the `elide-kotlin-maven-plugin` as a +drop-in replacement. It supports all configuration you would expect from the Kotlin Maven plugin. **`pom.xml`** ```xml - src/main/kotlin - src/test/kotlin dev.elide elide-kotlin-maven-plugin 1.0.0 - - - compile - - compile - - - - test-compile - - test-compile - - - + true @@ -82,89 +59,33 @@ the plugin coordinates: > [!TIP] > See the [Kotlin sample project](sample-kotlin) for a usage example. -### Mixed Java and Kotlin +### Java Compiler -By combining the Kotlin configuration and Java compiler replacement, mixed Java and Kotlin sources can be compiled with -Elide: +If you already have a complex project and just want the Elide Java compiler, you can set the `maven-compiler-plugin`'s +`compilerId` to `elide` to use Elide just as a Java compiler without using any plugins. **`pom.xml`** - ```xml - dev.elide - elide-kotlin-maven-plugin - 1.0.0 - - - compile - - compile - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/main/java - - - - - test-compile - - test-compile - - - - ${project.basedir}/src/test/kotlin - ${project.basedir}/src/test/java - - - - - - - org.apache.maven.plugins maven-compiler-plugin 3.15.0 dev.elide - elide-plexus-compilers + elide-java-compiler 1.0.0 elide - - - default-compile - none - - - default-testCompile - none - - - java-compile - compile - - compile - - - - java-test-compile - test-compile - - testCompile - - - ``` > [!TIP] -> See the [Mixed sources sample project](sample-mixed) for a usage example. \ No newline at end of file +> See the [Java sample project](sample-java) for a usage example. Elide also provides +> a [Gradle plugin](https://github.com/elide-dev/gradle). \ No newline at end of file diff --git a/elide-plugin/pom.xml b/elide-plugin/pom.xml new file mode 100644 index 0000000..45d319f --- /dev/null +++ b/elide-plugin/pom.xml @@ -0,0 +1,257 @@ + + + 4.0.0 + + dev.elide + elide-maven-plugin + 1.0.0 + maven-plugin + + Elide Maven Plugin + A Plugin that configures Maven to use Elide as a Java and Kotlin compiler. + https://elide.dev + + + + MIT License + https://www.opensource.org/licenses/mit-license.php + + + + + + Lauri Heino + datafox@datafox.me + Elide + https://elide.dev + + + + + scm:git:git://github.com/elide-dev/maven.git + scm:git:ssh://github.com:elide-dev/maven.git + https://github.com/elide-dev/maven/tree/main + + + + UTF-8 + official + 11 + + 1.0.0 + 2.3.21 + 1 + 2.16.2 + 6.0.3 + 3.9.15 + 3.15.2 + 3.5.5 + 3.15.0 + 4.0.3 + + 3.14.0 + + + 3.5.0 + 3.5.0 + 3.1.4 + 3.1.4 + 3.3.0 + 3.5.1 + 3.1.0 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + + + src/main/resources + true + + **/* + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${mavenToolsVersion} + + + default-descriptor + + descriptor + + process-classes + + + help-descriptor + + helpmojo + + process-classes + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlinVersion} + + + compile + + compile + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/main/java + + + + + test-compile + + test-compile + + + + ${project.basedir}/src/test/kotlin + ${project.basedir}/src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${mavenCompilerVersion} + + + dev.elide + elide-java-compiler + ${compilerVersion} + + + + elide + 11 + + + + default-compile + none + + + default-testCompile + none + + + java-compile + compile + + compile + + + + java-test-compile + test-compile + + testCompile + + + + + + maven-surefire-plugin + ${mavenTestPluginVersion} + + + maven-failsafe-plugin + ${mavenTestPluginVersion} + + + + + + + + + commons-io + commons-io + 2.22.0 + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + ${kotlinVersion} + test + + + org.junit.jupiter + junit-jupiter + ${junitVersion} + test + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlinVersion} + + + org.apache.maven + maven-plugin-api + ${mavenVersion} + provided + + + org.apache.maven + maven-core + ${mavenVersion} + provided + + + * + * + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${mavenCompilerKotlinPluginVersion} + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${mavenToolsVersion} + + + dev.elide + elide-java-compiler + ${compilerVersion} + + + dev.elide + elide-kotlin-maven-plugin + 1.0.0 + + + \ No newline at end of file diff --git a/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideCompileMojo.java b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideCompileMojo.java new file mode 100644 index 0000000..7504fce --- /dev/null +++ b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideCompileMojo.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Elide Java compiler Mojo. + * + * @author Lauri Heino + * @since 1.0.0 + */ +@Mojo( + name = "compile", + defaultPhase = LifecyclePhase.COMPILE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE) +public class ElideCompileMojo extends ElideCompileMojoImpl { +} diff --git a/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinJVMCompileMojo.java b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinJVMCompileMojo.java new file mode 100644 index 0000000..55c5403 --- /dev/null +++ b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinJVMCompileMojo.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin; + +import dev.elide.maven.plugin.kotlin.ElideKotlinJVMCompileMojoImpl; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Elide Kotlin to JVM compiler Mojo. + * + * @author Lauri Heino + * @since 1.0.0 + */ +@Mojo(name = "compile-kotlin", + defaultPhase = LifecyclePhase.COMPILE, + requiresDependencyResolution = ResolutionScope.COMPILE, + threadSafe = true) +public class ElideKotlinJVMCompileMojo extends ElideKotlinJVMCompileMojoImpl { +} diff --git a/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinJVMTestCompileMojo.java b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinJVMTestCompileMojo.java new file mode 100644 index 0000000..e1f1a1e --- /dev/null +++ b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinJVMTestCompileMojo.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin; + +import dev.elide.maven.plugin.kotlin.ElideKotlinJVMTestCompileMojoImpl; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Elide Kotlin to JVM test compiler Mojo. + * + * @author Lauri Heino + * @since 1.0.0 + */ +@Mojo(name = "test-compile-kotlin", + defaultPhase = LifecyclePhase.TEST_COMPILE, + requiresDependencyResolution = ResolutionScope.TEST, + threadSafe = true) +public class ElideKotlinJVMTestCompileMojo extends ElideKotlinJVMTestCompileMojoImpl { +} diff --git a/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinKaptJVMCompileMojo.java b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinKaptJVMCompileMojo.java new file mode 100644 index 0000000..f22179e --- /dev/null +++ b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinKaptJVMCompileMojo.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin; + +import dev.elide.maven.plugin.kotlin.ElideKotlinKaptJVMCompileMojoImpl; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Elide Kotlin Kapt JVM compiler Mojo. + * + * @author Lauri Heino + * @since 1.0.0 + */ +@Mojo(name = "kapt", + defaultPhase = LifecyclePhase.PROCESS_SOURCES, + requiresDependencyResolution = ResolutionScope.COMPILE) +public class ElideKotlinKaptJVMCompileMojo extends ElideKotlinKaptJVMCompileMojoImpl { +} diff --git a/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinKaptJVMTestCompileMojo.java b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinKaptJVMTestCompileMojo.java new file mode 100644 index 0000000..3f69843 --- /dev/null +++ b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideKotlinKaptJVMTestCompileMojo.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin; + +import dev.elide.maven.plugin.kotlin.ElideKotlinKaptJVMTestCompileMojoImpl; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Elide Kotlin Kapt JVM test compiler Mojo. + * + * @author Lauri Heino + * @since 1.0.0 + */ +@Mojo(name = "test-kapt", + defaultPhase = LifecyclePhase.PROCESS_TEST_SOURCES, + requiresDependencyResolution = ResolutionScope.TEST) +public class ElideKotlinKaptJVMTestCompileMojo extends ElideKotlinKaptJVMTestCompileMojoImpl { +} diff --git a/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideTestCompileMojo.java b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideTestCompileMojo.java new file mode 100644 index 0000000..7220775 --- /dev/null +++ b/elide-plugin/src/main/java/dev/elide/maven/plugin/ElideTestCompileMojo.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Elide Java test compiler Mojo. + * + * @author Lauri Heino + * @since 1.0.0 + */ +@Mojo( + name = "test-compile", + defaultPhase = LifecyclePhase.TEST_COMPILE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.TEST) +public class ElideTestCompileMojo extends ElideTestCompileMojoImpl { +} diff --git a/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideCompileMojoImpl.kt b/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideCompileMojoImpl.kt new file mode 100644 index 0000000..b3d1534 --- /dev/null +++ b/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideCompileMojoImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin + +import org.apache.maven.plugin.compiler.AbstractCompilerMojo +import org.apache.maven.plugin.compiler.CompilerMojo +import org.apache.maven.plugins.annotations.Parameter + +/** + * Elide Java compiler. + * + * @author Lauri Heino + * @since 1.0.0 + */ +open class ElideCompileMojoImpl : CompilerMojo() { + /** Elide executable location. */ + @Parameter(name = "executable") var executable: String? = null + + override fun execute() { + AbstractCompilerMojo::class.java.getDeclaredField("compilerId").apply { + isAccessible = true + set(this@ElideCompileMojoImpl, "elide") + } + executable?.let { + AbstractCompilerMojo::class.java.getDeclaredField("executable").apply { + isAccessible = true + set(this@ElideCompileMojoImpl, it) + } + } + super.execute() + } +} diff --git a/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideLifecycleParticipant.kt b/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideLifecycleParticipant.kt new file mode 100644 index 0000000..4cb2498 --- /dev/null +++ b/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideLifecycleParticipant.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin + +import dev.elide.maven.plugin.kotlin.ElideKotlinLifecycleParticipant + +/** + * Map [ElideKotlinLifecycleParticipant] to work as intended but use this plugin instead. + * + * @author Lauri Heino + * @since 1.0.0 + */ +open class ElideLifecycleParticipant : ElideKotlinLifecycleParticipant() { + init { + artifact = "elide-maven-plugin" + } +} diff --git a/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideTestCompileMojoImpl.kt b/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideTestCompileMojoImpl.kt new file mode 100644 index 0000000..32e9474 --- /dev/null +++ b/elide-plugin/src/main/kotlin/dev/elide/maven/plugin/ElideTestCompileMojoImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin + +import org.apache.maven.plugin.compiler.AbstractCompilerMojo +import org.apache.maven.plugin.compiler.TestCompilerMojo +import org.apache.maven.plugins.annotations.Parameter + +/** + * Elide Java test compiler. + * + * @author Lauri Heino + * @since 1.0.0 + */ +open class ElideTestCompileMojoImpl : TestCompilerMojo() { + /** Elide executable location. */ + @Parameter(name = "executable") var executable: String? = null + + override fun execute() { + AbstractCompilerMojo::class.java.getDeclaredField("compilerId").apply { + isAccessible = true + set(this@ElideTestCompileMojoImpl, "elide") + } + executable?.let { + AbstractCompilerMojo::class.java.getDeclaredField("executable").apply { + isAccessible = true + set(this@ElideTestCompileMojoImpl, it) + } + } + super.execute() + } +} diff --git a/elide-plugin/src/main/resources/META-INF/plexus/components.xml b/elide-plugin/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 0000000..5fc06bd --- /dev/null +++ b/elide-plugin/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,206 @@ + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + jar + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:test-compile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-jar-plugin:${mavenJarPluginVersion}:jar + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + ejb + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:test-compile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-ejb-plugin:${mavenEjbPluginVersion}:ejb + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + war + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:test-compile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-war-plugin:${mavenWarPluginVersion}:war + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + rar + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile-kotlin, + ${project.groupId}:${project.artifactId}:${project.version}:test-compile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-rar-plugin:${mavenJarPluginVersion}:rar + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.AbstractMavenLifecycleParticipant + kotlin + dev.elide.maven.plugin.ElideLifecycleParticipant + + + \ No newline at end of file diff --git a/kotlin-plugin/src/test/kotlin/.gitkeep b/elide-plugin/src/test/kotlin/.gitkeep similarity index 100% rename from kotlin-plugin/src/test/kotlin/.gitkeep rename to elide-plugin/src/test/kotlin/.gitkeep diff --git a/plexus-compilers/pom.xml b/java-compiler/pom.xml similarity index 83% rename from plexus-compilers/pom.xml rename to java-compiler/pom.xml index 4d5bb6d..8f4fdef 100644 --- a/plexus-compilers/pom.xml +++ b/java-compiler/pom.xml @@ -5,7 +5,7 @@ 4.0.0 dev.elide - elide-plexus-compilers + elide-java-compiler 1.0.0 jar @@ -52,6 +52,8 @@ 6.0.3 3.5.5 4.0.3 + 1.5.0 + 33.6.0-jre @@ -90,22 +92,17 @@ plexus-utils ${plexusUtilsVersion} + + + com.google.guava + guava + ${guavaVersion} + test + - - org.jetbrains.kotlin - kotlin-test-junit5 - ${kotlinVersion} - test - - - org.junit.jupiter - junit-jupiter - ${junitVersion} - test - org.jetbrains.kotlin kotlin-stdlib @@ -121,5 +118,28 @@ plexus-compiler-api ${plexusVersion} + + org.codehaus.plexus + plexus-compiler-javac + ${plexusVersion} + + + org.jetbrains.kotlin + kotlin-test-junit5 + ${kotlinVersion} + test + + + org.junit.jupiter + junit-jupiter + ${junitVersion} + test + + + org.codehaus.plexus + plexus-testing + ${plexusTestingVersion} + test + \ No newline at end of file diff --git a/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/Constants.kt b/java-compiler/src/main/kotlin/dev/elide/maven/compiler/Constants.kt similarity index 68% rename from plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/Constants.kt rename to java-compiler/src/main/kotlin/dev/elide/maven/compiler/Constants.kt index 1131d0d..b3437d6 100644 --- a/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/Constants.kt +++ b/java-compiler/src/main/kotlin/dev/elide/maven/compiler/Constants.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -12,7 +12,7 @@ */ package dev.elide.maven.compiler -/** - * Constant ID used by the Elide compiler shim. - */ -public const val ELIDE_COMPILER: String = "elide" +/** Constant ID used by the Elide compiler shim. */ +const val ELIDE_COMPILER: String = "elide" + +val ELIDE_EXECUTABLE: String = if (System.getProperty("os.name").contains("windows", true)) "elide.exe" else "elide" diff --git a/java-compiler/src/main/kotlin/dev/elide/maven/compiler/ElideJavacCompiler.kt b/java-compiler/src/main/kotlin/dev/elide/maven/compiler/ElideJavacCompiler.kt new file mode 100644 index 0000000..48f83d9 --- /dev/null +++ b/java-compiler/src/main/kotlin/dev/elide/maven/compiler/ElideJavacCompiler.kt @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.compiler + +import org.codehaus.plexus.compiler.CompilerConfiguration +import org.codehaus.plexus.compiler.CompilerException +import org.codehaus.plexus.compiler.CompilerMessage +import org.codehaus.plexus.compiler.CompilerResult +import org.codehaus.plexus.compiler.javac.JavacCompiler +import org.codehaus.plexus.util.StringUtils +import org.codehaus.plexus.util.cli.CommandLineException +import org.codehaus.plexus.util.cli.CommandLineUtils +import org.codehaus.plexus.util.cli.Commandline +import java.io.BufferedReader +import java.io.File +import java.io.IOException +import java.io.StringReader +import javax.inject.Named +import javax.inject.Singleton +import kotlin.io.path.absolutePathString + +/** + * Implements a Java compiler bridge from Maven to Elide. + * + * @author Lauri Heino + * @author Sam Gammon + * @since 1.0.0 + */ +@Named(ELIDE_COMPILER) +@Singleton +open class ElideJavacCompiler : JavacCompiler() { + override fun getCompilerId(): String = "elide" + + override fun performCompile(config: CompilerConfiguration): CompilerResult { + config.isFork = true + + val destinationDir = File(config.outputLocation) + if (!destinationDir.exists()) destinationDir.mkdirs() + + val sourceFiles = getSourceFiles(config) + if (sourceFiles == null || sourceFiles.size == 0) return CompilerResult() + + logCompiling(sourceFiles, config) + + val executable = getElideExecutable(config) + val javacVersion = getElideJavacVersion(executable) + val args = buildCompilerArguments(config, sourceFiles, javacVersion) + + return compileOutOfProcess(config, executable, args) + } + + override fun compileOutOfProcess( + config: CompilerConfiguration, + executable: String, + args: Array, + ): CompilerResult { + val cli = Commandline() + + cli.setWorkingDirectory(config.workingDirectory.absolutePath) + cli.setExecutable(executable) + + try { + val argumentsFile = + JavacCompiler::class + .java + .getDeclaredMethod("createFileWithArguments", Array::class.java, String::class.java) + .run { + isAccessible = true + invoke(this@ElideJavacCompiler, args, config.buildDirectory.absolutePath) as File + } + cli.addArguments( + arrayOf("javac", "--", "@" + argumentsFile.getCanonicalPath().replace(File.separatorChar, '/')) + ) + + if (!StringUtils.isEmpty(config.maxmem)) cli.addArguments(arrayOf("-J-Xmx${config.maxmem}")) + if (!StringUtils.isEmpty(config.meminitial)) cli.addArguments(arrayOf("-J-Xms${config.meminitial}")) + + for (key in config.getCustomCompilerArgumentsAsMap().keys) { + if (StringUtils.isNotEmpty(key) && key.startsWith("-J")) cli.addArguments(arrayOf(key)) + } + } catch (e: IOException) { + throw CompilerException("Error creating file with javac arguments", e) + } + + val out = CommandLineUtils.StringStreamConsumer() + val returnCode: Int + val messages: List + + try { + returnCode = CommandLineUtils.executeCommandLine(cli, out, out) + + if (log.isDebugEnabled) log.debug("Compiler output:{}{}", EOL, out.output) + + messages = + JavacCompiler::class + .java + .getDeclaredMethod("parseModernStream", Int::class.java, BufferedReader::class.java) + .run { + isAccessible = true + @Suppress("UNCHECKED_CAST") + invoke(null, returnCode, BufferedReader(StringReader(out.output))) + as MutableList + } + val last = + out.output.lines().reversed().let { + for (line in it) if (line.isNotBlank()) return@let line + "" + } + if (last.isNotBlank()) { + if (last.contains("✅")) messages.add(CompilerMessage(last, CompilerMessage.Kind.NOTE)) + else if (last.contains("❌")) messages.add(CompilerMessage(last, CompilerMessage.Kind.ERROR)) + } + } catch (e: CommandLineException) { + throw CompilerException("Error while executing the Elide javac compiler.", e) + } catch (e: IOException) { + throw CompilerException("Error while executing the Elide javac compiler.", e) + } + + val success = returnCode == 0 + return CompilerResult(success, messages) + } + + private fun getElideExecutable(config: CompilerConfiguration): String = + config.executable ?: ElideLocator.locate()?.absolutePathString() ?: ELIDE_EXECUTABLE + + internal fun getElideJavacVersion(executable: String): String? { + val cli = Commandline() + cli.setExecutable(executable) + cli.addArguments(arrayOf("javac", "--", "-version")) + val out = mutableListOf() + val err = mutableListOf() + try { + val exitCode = CommandLineUtils.executeCommandLine(cli, out::add, err::add) + if (exitCode != 0) { + throw CompilerException( + buildString { + append("Could not retrieve version from ") + append(executable) + append(". Exit code ") + append(exitCode) + append(", Output: ") + append(out.joinToString(System.lineSeparator())) + append(", Error: ") + append(err.joinToString(System.lineSeparator())) + } + ) + } + } catch (e: CommandLineException) { + throw CompilerException("Error while executing the external compiler $executable", e) + } + return tryParseVersion(out) ?: tryParseVersion(err) + } + + private fun tryParseVersion(versions: List): String? { + for (version in versions) { + val match = VERSION_RE.find(version) ?: continue + return match.value.substringBefore('.') + } + return null + } + + companion object { + val VERSION_RE = "\\d+\\.\\d+\\.\\d+".toRegex() + } +} diff --git a/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/ElideLocator.kt b/java-compiler/src/main/kotlin/dev/elide/maven/compiler/ElideLocator.kt similarity index 82% rename from plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/ElideLocator.kt rename to java-compiler/src/main/kotlin/dev/elide/maven/compiler/ElideLocator.kt index 0ee1bec..536c740 100644 --- a/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/ElideLocator.kt +++ b/java-compiler/src/main/kotlin/dev/elide/maven/compiler/ElideLocator.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -12,7 +12,7 @@ */ package dev.elide.maven.compiler -import java.io.File +import java.io.File.pathSeparatorChar import java.nio.file.Path import java.nio.file.Paths @@ -23,7 +23,7 @@ import java.nio.file.Paths * @since 1.0.0 */ object ElideLocator { - // Checks if a path is a valid binary. + /** Checks if a path is a valid binary. */ private fun isValidElideBinary(path: Path): Boolean { return path.toFile().exists() && path.toFile().isFile && path.toFile().canExecute() } @@ -35,8 +35,8 @@ object ElideLocator { */ fun locate(): Path? { val path = System.getenv("PATH") ?: "" - for (pathCandidate in path.split(File.separatorChar)) { - val candidate = Paths.get(pathCandidate, "elide") + for (pathCandidate in path.split(pathSeparatorChar)) { + val candidate = Paths.get(pathCandidate, ELIDE_EXECUTABLE) if (isValidElideBinary(candidate)) { return candidate } diff --git a/plexus-compilers/src/main/resources/META-INF/sisu/javax.inject.Named b/java-compiler/src/main/resources/META-INF/sisu/javax.inject.Named similarity index 100% rename from plexus-compilers/src/main/resources/META-INF/sisu/javax.inject.Named rename to java-compiler/src/main/resources/META-INF/sisu/javax.inject.Named diff --git a/java-compiler/src/test/kotlin/dev/elide/maven/compiler/ElideJavacCompilerTest.kt b/java-compiler/src/test/kotlin/dev/elide/maven/compiler/ElideJavacCompilerTest.kt new file mode 100644 index 0000000..559bc34 --- /dev/null +++ b/java-compiler/src/test/kotlin/dev/elide/maven/compiler/ElideJavacCompilerTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.compiler + +import org.codehaus.plexus.testing.PlexusTest +import org.codehaus.plexus.util.cli.CommandLineUtils +import org.codehaus.plexus.util.cli.Commandline +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.assertDoesNotThrow +import java.nio.file.Path +import kotlin.io.path.absolutePathString +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +/** + * Tests for the Elide Java Plexus Compiler. + * + * @author Lauri Heino + */ +@PlexusTest +class ElideJavacCompilerTest { + @Test + fun `can retrieve elide javac version`() { + val compiler = ElideJavacCompiler() + val version = + assertNotNull( + compiler.getElideJavacVersion(ELIDE_PATH.absolutePathString()), + "Elide javac version could not be retrieved", + ) + val versionInt = assertDoesNotThrow("Retrieved version should be an integer") { version.toInt() } + assertTrue(versionInt >= 25, "Retrieved version should be 25 or higher") + } + + companion object { + private lateinit var elidePath: Path + + val ELIDE_PATH by lazy { elidePath } + + val ELIDE_VERSION_RE = "\\d+\\.\\d+\\.\\d+(-.*)?".toRegex() + + @BeforeAll + @JvmStatic + fun `elide should be present for tests`() { + elidePath = assertNotNull(ElideLocator.locate(), "Elide binary was not found") + val cli = Commandline() + cli.executable = elidePath.absolutePathString() + cli.addArguments(arrayOf("--version")) + val out = CommandLineUtils.StringStreamConsumer() + assertDoesNotThrow("Could not run elide binary") { + val code = CommandLineUtils.executeCommandLine(cli, out, out) + assertEquals(0, code, "Elide binary produced an error: ${out.output}") + } + val lines = out.output.lineSequence().filter(String::isNotBlank).toList() + assertEquals(1, lines.size, "Output should contain a single non-blank line") + assertTrue(lines.first().trim().matches(ELIDE_VERSION_RE), "Output should be a valid Elide version") + } + } +} diff --git a/kotlin-plugin/pom.xml b/kotlin-plugin/pom.xml index 8a0b829..16a649d 100644 --- a/kotlin-plugin/pom.xml +++ b/kotlin-plugin/pom.xml @@ -10,7 +10,8 @@ maven-plugin Elide Kotlin Maven Plugin - A drop-in replacement for the Kotlin Maven Plugin that uses Elide to compile Kotlin sources. + A drop-in replacement for the Kotlin Maven Plugin that uses Elide to compile Kotlin sources. + https://elide.dev @@ -50,6 +51,15 @@ 3.5.5 3.15.0 4.0.3 + + + 3.5.0 + 3.5.0 + 3.1.4 + 3.1.4 + 3.3.0 + 3.5.1 + 3.1.0 @@ -60,6 +70,16 @@ + + + src/main/resources + true + + **/* + + + + org.apache.maven.plugins @@ -120,7 +140,7 @@ dev.elide - elide-plexus-compilers + elide-java-compiler ${compilerVersion} @@ -166,12 +186,6 @@ - - - org.codehaus.plexus - plexus-utils - ${plexusUtilsVersion} - commons-io @@ -227,37 +241,10 @@ maven-plugin-annotations ${mavenToolsVersion} - - org.jetbrains.kotlin - kotlin-build-tools-api - ${kotlinVersion} - compile - - - org.jetbrains.kotlin - kotlin-build-tools-impl - ${kotlinVersion} - runtime - - - org.jetbrains.kotlin - kotlin-compiler-embeddable - ${kotlinVersion} - - - org.jetbrains.kotlin - kotlin-scripting-compiler-embeddable - ${kotlinVersion} - dev.elide - elide-plexus-compilers + elide-java-compiler ${compilerVersion} - - javax.inject - javax.inject - ${injectVersion} - \ No newline at end of file diff --git a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojo.java b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojo.java index df28ea9..47c5cab 100644 --- a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojo.java +++ b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at diff --git a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojo.java b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojo.java index 074ca72..ab05f38 100644 --- a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojo.java +++ b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at diff --git a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojo.java b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojo.java index 0b618e1..67d7a11 100644 --- a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojo.java +++ b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at diff --git a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojo.java b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojo.java index 046d513..688a7c1 100644 --- a/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojo.java +++ b/kotlin-plugin/src/main/java/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ArgumentParser.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ArgumentParser.kt index 184629e..5b4cbcc 100644 --- a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ArgumentParser.kt +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ArgumentParser.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -25,20 +25,17 @@ import java.util.* * @since 1.0.0 */ object ArgumentParser { - /** - * Parses [A] into a list of Elide Kotlin compiler command line arguments. - */ + /** Parses [A] into a list of Elide Kotlin compiler command line arguments. */ fun parseArguments( compiler: String, arguments: A, project: MavenProject, - java: Boolean, ): Array { val list: MutableList = LinkedList() list.add(compiler) list.add("--") getAllFields(arguments::class.java).forEach { list.parseArgument(arguments, it) } - if (java && list.none { it == "-d" || it.startsWith("-d=") }) { + if (list.none { it == "-d" || it.startsWith("-d=") }) { list.add("-d") list.add(project.build.outputDirectory) } @@ -50,18 +47,19 @@ object ArgumentParser { private fun getAllFields(type: Class): List { var type: Class = type val fields: MutableList = LinkedList() - fields.addAll(type.declaredFields.filter { it.trySetAccessible() && it.isAnnotationPresent(Argument::class.java) }) - while(type != CommonCompilerArguments::class.java) { + fields.addAll( + type.declaredFields.filter { it.trySetAccessible() && it.isAnnotationPresent(Argument::class.java) } + ) + while (type != CommonCompilerArguments::class.java) { type = type.superclass as Class - fields.addAll(type.declaredFields.filter { it.trySetAccessible() && it.isAnnotationPresent(Argument::class.java) }) + fields.addAll( + type.declaredFields.filter { it.trySetAccessible() && it.isAnnotationPresent(Argument::class.java) } + ) } return fields } - private fun MutableList.parseArgument( - arguments: A, - field: Field, - ) { + private fun MutableList.parseArgument(arguments: A, field: Field) { val argument = field.getAnnotation(Argument::class.java) ?: return val element: Any = field.get(arguments) ?: return when (element) { diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojoImpl.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojoImpl.kt index ad5444c..44fabd2 100644 --- a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojoImpl.kt +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMCompileMojoImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -26,10 +26,8 @@ import java.io.File * @author Lauri Heino * @since 1.0.0 */ -internal open class ElideKotlinJVMCompileMojoImpl : K2JVMCompileMojo() { - /** - * Elide executable location. - */ +open class ElideKotlinJVMCompileMojoImpl : K2JVMCompileMojo() { + /** Elide executable location. */ @Parameter(name = "executable") var executable: String? = null override fun execCompiler( @@ -37,14 +35,5 @@ internal open class ElideKotlinJVMCompileMojoImpl : K2JVMCompileMojo() { messageCollector: MessageCollector, arguments: K2JVMCompilerArguments, sourceRoots: List, - ): ExitCode = - ElideRunner.runCompiler( - messageCollector, - arguments, - sourceRoots, - project, - executable, - "kotlinc", - true, - ) + ): ExitCode = ElideRunner.runCompiler(messageCollector, arguments, sourceRoots, project, executable, "kotlinc") } diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojoImpl.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojoImpl.kt index b1cc550..3ca79be 100644 --- a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojoImpl.kt +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinJVMTestCompileMojoImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -26,10 +26,8 @@ import java.io.File * @author Lauri Heino * @since 1.0.0 */ -internal open class ElideKotlinJVMTestCompileMojoImpl : KotlinTestCompileMojo() { - /** - * Elide executable location. - */ +open class ElideKotlinJVMTestCompileMojoImpl : KotlinTestCompileMojo() { + /** Elide executable location. */ @Parameter(name = "executable") var executable: String? = null override fun execCompiler( @@ -37,14 +35,5 @@ internal open class ElideKotlinJVMTestCompileMojoImpl : KotlinTestCompileMojo() messageCollector: MessageCollector, arguments: K2JVMCompilerArguments, sourceRoots: List, - ): ExitCode = - ElideRunner.runCompiler( - messageCollector, - arguments, - sourceRoots, - project, - executable, - "kotlinc", - true, - ) + ): ExitCode = ElideRunner.runCompiler(messageCollector, arguments, sourceRoots, project, executable, "kotlinc") } diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojoImpl.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojoImpl.kt index 90a2c1c..0a3ec3b 100644 --- a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojoImpl.kt +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMCompileMojoImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -26,10 +26,8 @@ import java.io.File * @author Lauri Heino * @since 1.0.0 */ -internal open class ElideKotlinKaptJVMCompileMojoImpl : KaptJVMCompilerMojo() { - /** - * Elide executable location. - */ +open class ElideKotlinKaptJVMCompileMojoImpl : KaptJVMCompilerMojo() { + /** Elide executable location. */ @Parameter(name = "executable") var executable: String? = null override fun execCompiler( @@ -37,14 +35,5 @@ internal open class ElideKotlinKaptJVMCompileMojoImpl : KaptJVMCompilerMojo() { messageCollector: MessageCollector, arguments: K2JVMCompilerArguments, sourceRoots: List, - ): ExitCode = - ElideRunner.runCompiler( - messageCollector, - arguments, - sourceRoots, - project, - executable, - "kotlinc", - true, - ) + ): ExitCode = ElideRunner.runCompiler(messageCollector, arguments, sourceRoots, project, executable, "kotlinc") } diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojoImpl.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojoImpl.kt index eea0176..fdd3698 100644 --- a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojoImpl.kt +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinKaptJVMTestCompileMojoImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -26,10 +26,8 @@ import java.io.File * @author Lauri Heino * @since 1.0.0 */ -internal open class ElideKotlinKaptJVMTestCompileMojoImpl : KaptTestJvmCompilerMojo() { - /** - * Elide executable location. - */ +open class ElideKotlinKaptJVMTestCompileMojoImpl : KaptTestJvmCompilerMojo() { + /** Elide executable location. */ @Parameter(name = "executable") var executable: String? = null override fun execCompiler( @@ -37,14 +35,5 @@ internal open class ElideKotlinKaptJVMTestCompileMojoImpl : KaptTestJvmCompilerM messageCollector: MessageCollector, arguments: K2JVMCompilerArguments, sourceRoots: List, - ): ExitCode = - ElideRunner.runCompiler( - messageCollector, - arguments, - sourceRoots, - project, - executable, - "kotlinc", - true, - ) + ): ExitCode = ElideRunner.runCompiler(messageCollector, arguments, sourceRoots, project, executable, "kotlinc") } diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinLifecycleParticipant.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinLifecycleParticipant.kt new file mode 100644 index 0000000..19a5d8d --- /dev/null +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinLifecycleParticipant.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin.kotlin + +import org.apache.maven.execution.MavenSession +import org.apache.maven.model.Plugin +import org.apache.maven.project.MavenProject +import org.jetbrains.kotlin.maven.KotlinLifecycleParticipant + +/** + * Map [KotlinLifecycleParticipant] to work as intended but use this plugin instead. + * + * @author Lauri Heino + * @since 1.0.0 + */ +open class ElideKotlinLifecycleParticipant : KotlinLifecycleParticipant() { + var artifact: String = ELIDE_KOTLIN_PLUGIN_ARTIFACT_ID + + override fun afterProjectsRead(session: MavenSession) { + // using reflection here to avoid copying the entire parent class + for (project in session.projects) { + val plugin = getElideKotlinMavenPlugin(project) + if ( + plugin != null && + callPrivateFuncBoolean("isExtensionsEnabled", plugin.callArg()) && + callPrivateFuncBoolean("isSmartDefaultsEnabled", project.callArg()) + ) { + callPrivateFunc( + "configureSmartDefaults", + project.callArg(), + plugin.callArg(), + ) + } + } + } + + fun getElideKotlinMavenPlugin(project: MavenProject): Plugin? { + for (plugin in project.getBuildPlugins()) { + if (ELIDE_GROUP_ID == plugin.groupId && artifact == plugin.artifactId) { + return plugin + } + } + return null + } + + inline fun T.callPrivateFuncBoolean( + name: String, + vararg args: Pair, out Any?>, + ): Boolean = + T::class.java.getDeclaredMethod(name, *args.map { it.first }.toTypedArray()).run { + isAccessible = true + invoke(this@ElideKotlinLifecycleParticipant, *args.map { it.second }.toTypedArray()) as Boolean + } + + inline fun T.callPrivateFunc(name: String, vararg args: Pair, out Any?>) { + T::class.java.getDeclaredMethod(name, *args.map { it.first }.toTypedArray()).apply { + isAccessible = true + invoke(this@ElideKotlinLifecycleParticipant, *args.map { it.second }.toTypedArray()) + } + } + + inline fun T.callArg() = Pair(T::class.java, this) + + companion object { + const val ELIDE_GROUP_ID = "dev.elide" + const val ELIDE_KOTLIN_PLUGIN_ARTIFACT_ID = "elide-kotlin-maven-plugin" + } +} diff --git a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideRunner.kt b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideRunner.kt index 364a00d..bc510a9 100644 --- a/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideRunner.kt +++ b/kotlin-plugin/src/main/kotlin/dev/elide/maven/plugin/kotlin/ElideRunner.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2025 Elide Technologies, Inc. + * Copyright (c) 2024-2026 Elide Technologies, Inc. * * Licensed under the MIT license (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at @@ -12,6 +12,7 @@ */ package dev.elide.maven.plugin.kotlin +import dev.elide.maven.compiler.ELIDE_EXECUTABLE import dev.elide.maven.compiler.ElideLocator import org.apache.maven.project.MavenProject import org.codehaus.plexus.compiler.CompilerException @@ -33,9 +34,7 @@ import kotlin.io.path.absolutePathString * @since 1.0.0 */ object ElideRunner { - /** - * Executes the Elide Kotlin compiler according to [arguments]. - */ + /** Executes the Elide Kotlin compiler according to [arguments]. */ fun runCompiler( messageCollector: MessageCollector, arguments: A, @@ -43,7 +42,6 @@ object ElideRunner { project: MavenProject, executable: String?, compiler: String, - java: Boolean, ): ExitCode { val freeArgs = arguments.freeArgs.toMutableList() for (sourceRoot in sourceRoots) { @@ -52,16 +50,15 @@ object ElideRunner { arguments.freeArgs = freeArgs val cli = Commandline() cli.workingDirectory = project.basedir - cli.executable = executable ?: ElideLocator.locate()?.absolutePathString() ?: "elide" - cli.addArguments(ArgumentParser.parseArguments(compiler, arguments, project, java)) + cli.executable = executable ?: ElideLocator.locate()?.absolutePathString() ?: ELIDE_EXECUTABLE + cli.addArguments(ArgumentParser.parseArguments(compiler, arguments, project)) val out = CommandLineUtils.StringStreamConsumer() var returnCode: Int try { returnCode = CommandLineUtils.executeCommandLine(cli, out, out) out.output.lines().forEach { messageCollector.report( - if (returnCode == 0) CompilerMessageSeverity.INFO - else CompilerMessageSeverity.ERROR, + if (returnCode == 0) CompilerMessageSeverity.INFO else CompilerMessageSeverity.ERROR, it, ) } diff --git a/kotlin-plugin/src/main/resources/META-INF/plexus/components.xml b/kotlin-plugin/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 0000000..14eb5ed --- /dev/null +++ b/kotlin-plugin/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,206 @@ + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + jar + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:testCompile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-jar-plugin:${mavenJarPluginVersion}:jar + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + ejb + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:testCompile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-ejb-plugin:${mavenEjbPluginVersion}:ejb + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + war + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:testCompile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-war-plugin:${mavenWarPluginVersion}:war + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + rar + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + + + ${project.groupId}:${project.artifactId}:${project.version}:kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:resources + + + ${project.groupId}:${project.artifactId}:${project.version}:compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:compile + + + ${project.groupId}:${project.artifactId}:${project.version}:test-kapt + + + org.apache.maven.plugins:maven-resources-plugin:${mavenResourcesPluginVersion}:testResources + + + ${project.groupId}:${project.artifactId}:${project.version}:test-compile, + org.apache.maven.plugins:maven-compiler-plugin:${mavenCompilerVersion}:testCompile + + + org.apache.maven.plugins:maven-surefire-plugin:${mavenTestPluginVersion}:test + + + org.apache.maven.plugins:maven-rar-plugin:${mavenRarPluginVersion}:rar + + + org.apache.maven.plugins:maven-install-plugin:${mavenInstallPluginVersion}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${mavenDeployPluginVersion}:deploy + + + + + + + + + + org.apache.maven.AbstractMavenLifecycleParticipant + kotlin + dev.elide.maven.plugin.kotlin.ElideKotlinLifecycleParticipant + + + \ No newline at end of file diff --git a/kotlin-plugin/src/test/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinPluginTest.kt b/kotlin-plugin/src/test/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinPluginTest.kt new file mode 100644 index 0000000..23320ac --- /dev/null +++ b/kotlin-plugin/src/test/kotlin/dev/elide/maven/plugin/kotlin/ElideKotlinPluginTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024-2026 Elide Technologies, Inc. + * + * Licensed under the MIT license (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://opensource.org/license/mit/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under the License. + */ +package dev.elide.maven.plugin.kotlin + +import org.apache.maven.project.MavenProject +import org.jetbrains.kotlin.cli.common.arguments.Argument +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArgumentsConfigurator +import kotlin.test.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +/** + * Tests for the Elide Kotlin Maven Plugin. + * + * @author Lauri Heino + */ +class ElideKotlinPluginTest { + @Test + fun `argument parser should parse arguments`() { + val arguments = MockCompilerArguments(CommonCompilerArgumentsConfigurator()) + arguments.someSpecialArgument = "gargantuan" + val project = MavenProject() + project.build.outputDirectory = "output/directory" + val parsedArguments = ArgumentParser.parseArguments("test", arguments, project) + assertEquals("test", parsedArguments[0]) + assertEquals("--", parsedArguments[1]) + assertContains(parsedArguments, "-XXspecial-argument=gargantuan") + val dIndex = parsedArguments.indexOf("-d") + assertNotEquals(-1, dIndex) + assertEquals("output/directory", parsedArguments[dIndex + 1]) + } + + class MockCompilerArguments(override val configurator: CommonCompilerArgumentsConfigurator) : + CommonCompilerArguments() { + @Argument(value = "-XXspecial-argument", valueDescription = "", description = "This is just for testing.") + var someSpecialArgument: String? = null + set(value) { + checkFrozen() + field = if (value.isNullOrEmpty()) null else value + } + } +} diff --git a/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/ElideJavacCompiler.kt b/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/ElideJavacCompiler.kt deleted file mode 100644 index ca47697..0000000 --- a/plexus-compilers/src/main/kotlin/dev/elide/maven/compiler/ElideJavacCompiler.kt +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2024-2025 Elide Technologies, Inc. - * - * Licensed under the MIT license (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://opensource.org/license/mit/ - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under the License. - */ -package dev.elide.maven.compiler - -import org.codehaus.plexus.compiler.* -import org.codehaus.plexus.util.cli.CommandLineException -import org.codehaus.plexus.util.cli.CommandLineUtils -import org.codehaus.plexus.util.cli.Commandline -import java.io.File -import java.io.IOException -import java.util.LinkedList -import javax.inject.Named -import javax.inject.Singleton -import kotlin.io.path.absolutePathString - -/** - * Implements a Java compiler bridge from Maven to Elide. - * - * @author Lauri Heino - * @author Sam Gammon - * @since 1.0.0 - */ -@Named(ELIDE_COMPILER) -@Singleton -public open class ElideJavacCompiler() : AbstractCompiler( - CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, - ".java", - ".class", - null -) { - override fun getCompilerId(): String = "elide" - - override fun performCompile(config: CompilerConfiguration): CompilerResult { - val dest = File(config.outputLocation) - if(!dest.exists()) dest.mkdirs() - val sources = getSourceFiles(config) ?: return CompilerResult() - if(sources.isEmpty()) return CompilerResult() - logCompiling(sources, config) - val executable = getElideExecutable(config) - val args = buildList { - addAll(buildElideArgs(config, sources)) - config.maxmem?.ifEmpty { null }?.let { add("-J-Xmx$this") } - config.meminitial?.ifEmpty { null }?.let { add("-J-Xms$this") } - - config.customCompilerArgumentsAsMap.entries - .filter { it.value != null && it.key.startsWith("-J") } - .ifEmpty { null } - ?.forEach { add("${it.key}=${it.value}") } - } - - val cli = Commandline() - cli.setWorkingDirectory(config.workingDirectory.absolutePath) - cli.executable = executable - config.customCompilerArgumentsAsMap.keys - .filter { it != null && it.startsWith("-J") } - .apply { if(isNotEmpty()) cli.addArguments(toTypedArray()) } - - cli.addArguments(args.toTypedArray()) - val out = CommandLineUtils.StringStreamConsumer() - var returnCode: Int - val messages: List - try { - returnCode = CommandLineUtils.executeCommandLine(cli, out, out) - messages = parseOutput(returnCode, out.output.lines()) - } catch(e: CommandLineException) { - throw CompilerException("Error while executing Elide javac compiler.", e) - } catch(e: IOException) { - throw CompilerException("Error while executing Elide javac compiler.", e) - } - return CompilerResult(returnCode == 0, messages) - } - - private fun getElideExecutable(config: CompilerConfiguration): String = when (val executable = config.executable) { - null -> ElideLocator.locate()?.absolutePathString() - else -> executable - } ?: "elide" - - override fun createCommandLine(config: CompilerConfiguration): Array { - return buildElideArgs(config, getSourceFiles(config)).toTypedArray() - } - - private fun buildElideArgs(config: CompilerConfiguration, sources: Array): MutableList { - val args: MutableList = LinkedList() - args.add("javac") - args.add("--") - val destinationDir = File(config.outputLocation) - args.add("-d") - args.add(destinationDir.absolutePath) - config.classpathEntries?.ifEmpty { null }?.let { - args.add("-classpath") - args.add(getPathString(it)) - } - config.modulepathEntries?.ifEmpty { null }?.let { - args.add("--module-path") - args.add(getPathString(it)) - } - config.sourceLocations?.ifEmpty { null }?.let { - args.add("-sourcepath") - args.add(getPathString(it)) - } - args.addAll(listOf(*sources)) - - config.generatedSourcesDirectory.apply { - mkdirs() - args.add("-s") - args.add(absolutePath) - } - config.proc?.apply { args.add("-proc:$this") } - config.annotationProcessors?.apply { - args.add("-processor") - args.add(indices.joinToString(",") { this[it] }) - } - config.processorPathEntries?.ifEmpty { null }?.let { - args.add("-processorpath") - args.add(getPathString(it)) - } - config.processorModulePathEntries?.ifEmpty { null }?.let { - args.add("--processor-module-path") - args.add(getPathString(it)) - } - if (config.isOptimize) args.add("-O") - if (config.isDebug) { - if (config.debugLevel?.isNotEmpty() == true) { - args.add("-g:" + config.debugLevel) - } else { - args.add("-g") - } - } - if (config.isVerbose) args.add("-verbose") - if (config.isParameters) args.add("-parameters") - if (config.isEnablePreview) args.add("--enable-preview") - config.implicitOption?.apply { args.add("-implicit:$this") } - if (config.isShowDeprecation) { - args.add("-deprecation") - config.isShowWarnings = true - } - if (!config.isShowWarnings) { - args.add("-nowarn") - } else { - val warnings = config.warnings - if (config.isShowLint) { - if (warnings.isNotEmpty()) { - args.add("-Xlint:$warnings") - } else { - args.add("-Xlint") - } - } - } - if (config.isFailOnWarning) args.add("-Werror") - if (config.releaseVersion?.isNotEmpty() == true) { - args.add("--release") - args.add(config.releaseVersion) - } else { - if (config.targetVersion?.isEmpty() == true) { - args.add("-target") - args.add("1.1") - } else { - args.add("-target") - args.add(config.targetVersion) - } - if (config.sourceVersion?.isEmpty() == true) { - args.add("-source") - args.add("1.3") - } else { - args.add("-source") - args.add(config.sourceVersion) - } - } - config.sourceEncoding?.ifEmpty { null }?.let { - args.add("-encoding") - args.add(it) - } - config.moduleVersion?.ifEmpty { null }?.let { - args.add("--module-version") - args.add(it) - } - config.customCompilerArgumentsEntries?.forEach { (key, value) -> - if (key.isEmpty() || key.startsWith("-J")) return@forEach - args.add(key) - if (value.isNotEmpty()) args.add(value) - } - return args - } - - @Throws(IOException::class) - private fun parseOutput(exitCode: Int, input: List): List { - //very lazy for now - val kind = if(exitCode == 0) CompilerMessage.Kind.NOTE else CompilerMessage.Kind.ERROR - return input.map { CompilerMessage(it, kind) } - } -} diff --git a/plexus-compilers/src/test/kotlin/.gitkeep b/plexus-compilers/src/test/kotlin/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/pom.xml b/pom.xml index 9d3629a..bf0e055 100644 --- a/pom.xml +++ b/pom.xml @@ -10,10 +10,8 @@ pom - plexus-compilers + java-compiler kotlin-plugin - sample-java - sample-kotlin - sample-mixed + elide-plugin \ No newline at end of file diff --git a/sample-java/README.md b/sample-java/README.md index 15340a9..52be430 100644 --- a/sample-java/README.md +++ b/sample-java/README.md @@ -1,7 +1,7 @@ ## Elide Maven Java Compiler: Sample project This project demonstrates use of Elide as a replacement for `javac` within a Maven project. Explicitly add the -`maven-compiler-plugin`, add `elide-plexus-compilers` as a dependency, and configure `compilerId` to `elide`. +`maven-compiler-plugin`, add `elide-java-compiler` as a dependency, and configure `compilerId` to `elide`. **`pom.xml`** ```xml @@ -13,7 +13,7 @@ This project demonstrates use of Elide as a replacement for `javac` within a Mav dev.elide - elide-plexus-compilers + elide-java-compiler 1.0.0 diff --git a/sample-java/pom.xml b/sample-java/pom.xml index 6fda217..808b73d 100644 --- a/sample-java/pom.xml +++ b/sample-java/pom.xml @@ -14,7 +14,7 @@ dev.elide - elide-plexus-compilers + elide-java-compiler 1.0.0 @@ -22,6 +22,21 @@ elide + + org.codehaus.mojo + exec-maven-plugin + 3.6.3 + + + + java + + + + + com.sample.Hello + + diff --git a/sample-kotlin/README.md b/sample-kotlin/README.md index 78636bb..ea157bc 100644 --- a/sample-kotlin/README.md +++ b/sample-kotlin/README.md @@ -2,7 +2,7 @@ This project demonstrates use of Elide as a Kotlin compiler within a Maven project. This is a drop-in replacement for the Kotlin plugin, so configure your Kotlin project like normal, but use `dev.elide:elide-kotlin-maven-plugin` instead -of `org.jetbrains.kotlin:kotlin-maven-plugin`. Use of `` is not supported yet. +of `org.jetbrains.kotlin:kotlin-maven-plugin`. **`pom.xml`** ```xml @@ -14,20 +14,7 @@ of `org.jetbrains.kotlin:kotlin-maven-plugin`. Use of `` is not supp dev.elide elide-kotlin-maven-plugin 1.0.0 - - - compile - - compile - - - - test-compile - - test-compile - - - + true diff --git a/sample-kotlin/pom.xml b/sample-kotlin/pom.xml index 43c5e85..16f033e 100644 --- a/sample-kotlin/pom.xml +++ b/sample-kotlin/pom.xml @@ -22,31 +22,23 @@ dev.elide elide-kotlin-maven-plugin 1.0.0 + true + + + org.codehaus.mojo + exec-maven-plugin + 3.6.3 - compile - compile - - - - - test-compile - - test-compile + java + + com.sample.HelloKt + - - - - org.jetbrains.kotlin - kotlin-stdlib - 2.3.21 - - - \ No newline at end of file diff --git a/sample-mixed/README.md b/sample-mixed/README.md index 6d7803c..34a56ce 100644 --- a/sample-mixed/README.md +++ b/sample-mixed/README.md @@ -1,10 +1,7 @@ ## Elide Maven Kotlin Plugin: Mixed sources sample project -This project demonstrates use of Elide as a Java and Kotlin compiler within a Maven project. This is a drop-in -replacement for the Kotlin plugin, so configure your Kotlin project like normal, but use -`dev.elide:elide-kotlin-maven-plugin` instead of `org.jetbrains.kotlin:kotlin-maven-plugin`, add -`elide-plexus-compilers` as a dependency to the `maven-compiler-plugin` and configure `compilerId` to `elide`. Use of -Kotlin plugin `` is not supported yet. +This project demonstrates use of Elide as a Java and Kotlin compiler within a Maven project. To configure it, simply add +the `dev.elide:elide-maven-plugin` and set `extensions` to `true`. **`pom.xml`** ```xml @@ -12,73 +9,9 @@ Kotlin plugin `` is not supported yet. dev.elide - elide-kotlin-maven-plugin + elide-maven-plugin 1.0.0 - - - compile - - compile - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/main/java - - - - - test-compile - - test-compile - - - - ${project.basedir}/src/test/kotlin - ${project.basedir}/src/test/java - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.15.0 - - - dev.elide - elide-plexus-compilers - 1.0.0 - - - - elide - - - - default-compile - none - - - default-testCompile - none - - - java-compile - compile - - compile - - - - java-test-compile - test-compile - - testCompile - - - + true diff --git a/sample-mixed/pom.xml b/sample-mixed/pom.xml index a93b2a9..bbde5eb 100644 --- a/sample-mixed/pom.xml +++ b/sample-mixed/pom.xml @@ -25,82 +25,25 @@ dev.elide - elide-kotlin-maven-plugin + elide-maven-plugin 1.0.0 - - - compile - - compile - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/main/java - - - - - test-compile - - test-compile - - - - ${project.basedir}/src/test/kotlin - ${project.basedir}/src/test/java - - - - + true - org.apache.maven.plugins - maven-compiler-plugin - 3.15.0 - - - dev.elide - elide-plexus-compilers - 1.0.0 - - - - elide - + org.codehaus.mojo + exec-maven-plugin + 3.6.3 - default-compile - none - - - default-testCompile - none - - - java-compile - compile - compile - - - - java-test-compile - test-compile - - testCompile + java + + com.sample.Hello + - - - - org.jetbrains.kotlin - kotlin-stdlib - 2.3.21 - - \ No newline at end of file diff --git a/sample-mixed/src/main/kotlin/com/sample/Library.kt b/sample-mixed/src/main/kotlin/com/sample/Library.kt index bb18a3f..95db1a3 100644 --- a/sample-mixed/src/main/kotlin/com/sample/Library.kt +++ b/sample-mixed/src/main/kotlin/com/sample/Library.kt @@ -2,4 +2,4 @@ package com.sample object Library { fun getHello(): String = "Hello, World!" -} \ No newline at end of file +}