Compare commits

...

63 commits
1.0.2 ... main

Author SHA1 Message Date
574205d548
Advance options should start with -X 2025-04-15 10:51:10 -07:00
9c633116dc
Bump JUnit to version 5.12.2 2025-04-12 18:48:21 -07:00
dfa9a6124e
Add method to find the Kotlin home 2025-04-01 11:19:17 -07:00
23a97601db
Find compiler in Kotlin home, if specified 2025-03-31 10:32:23 -07:00
2a406feb15
Add snap locations to common paths 2025-03-30 14:30:10 -07:00
5a3c77a162
Update extensions dependencies
Bump Exec from 1.0.4 to 1.0.5
Bump PMD from 1.2.1 to 1.2.2
2025-03-28 07:53:08 -07:00
852e24bc18
Log where the kotlin compiler was found from/at 2025-03-26 21:52:12 -07:00
8e2415eda4
Minor cleanups 2025-03-25 00:00:06 -07:00
bf82ea1920
Remove unnecessary isMinGW and isCygwin methods 2025-03-24 21:29:33 -07:00
b0ad8ad056
Read @argfile manually 2025-03-23 18:35:56 -07:00
b5b6b40564
Fix plugins paths for Windows/MacOS 2025-03-23 16:31:45 -07:00
74a180e6fd
Combine project and examples jobs 2025-03-23 15:23:12 -07:00
0990e82f04
Only check kotlinc arguments on Linux 2025-03-23 15:16:27 -07:00
dc5b81e366
Add isMinGW() and isCygwin() methods 2025-03-23 15:14:23 -07:00
5d78963f1d
Add macos-latest to examples OS matrix 2025-03-23 03:51:54 -07:00
e32ebf19d6
Download dependency for the examples in project workflow as needed for testing 2025-03-23 03:39:19 -07:00
96b8139b97
Add /usr/share common kotlinc paths 2025-03-23 03:33:48 -07:00
a7a9b10f97
Split project and examples jobs 2025-03-23 03:28:03 -07:00
f4ff095297
Use an OS matrix to run on 2025-03-23 03:21:27 -07:00
8251473b05
Run all matrices under Windows 2025-03-23 03:15:41 -07:00
bef5aed2e3
Move compile options to a var 2025-03-23 03:14:35 -07:00
a2a5f284b6
Add workflow for testing the examples on Windows 2025-03-23 03:00:00 -07:00
b0d6a3ac3b
Pass arguments to kotlinc via @argfile 2025-03-23 02:30:17 -07:00
125e9f7327
Move jvmOptions to main compile operation 2025-03-23 02:22:25 -07:00
3a012bf012
Cleanup Kotlin common paths 2025-03-22 10:16:18 -07:00
a21938f7b5
Log the Kotlin compiler location when found 2025-03-21 23:15:20 -07:00
b8927615ec
1.1.0-SNAPSHOT 2025-03-21 21:29:04 -07:00
e7d0ada68c
Reorder the common kotlin compiler potential locations 2025-03-21 21:24:44 -07:00
a57ae52a1c
Add method to locate the Kotlin compiler in common locations 2025-03-21 21:08:56 -07:00
9fcc5cc362
Add test for fromProject() using the examples project 2025-03-21 21:04:34 -07:00
54228e3149
Add tests for new compiler plugins 2025-03-21 11:35:12 -07:00
5ca06f4d81
Add support for illegal native access modes 2025-03-21 11:29:44 -07:00
779e6d4b79
Change List to Collection 2025-03-21 01:32:03 -07:00
3c5b1fde8f
Implement JvmOptions class 2025-03-21 01:04:54 -07:00
832447771d
Add Compose and Imports Dumper compiler plugins 2025-03-21 01:04:53 -07:00
48c896f0df
Bump Kotlin to version 2.1.20 2025-03-21 01:04:42 -07:00
31e4208d7f
JDK 24 2025-03-18 23:37:48 -07:00
d8c1049990
Add generic installation instructions 2025-03-18 12:30:20 -07:00
0f6385e3f3
Bump JUnit to version 5.12.1 2025-03-18 04:18:20 -07:00
323f96b54b
Bump PMD extension to version 1.2.1 2025-03-18 04:17:48 -07:00
048efcb810
Bump bld to version 2.2.1 2025-02-25 09:43:06 -08:00
80f00b41ed
Bump JUnit to version 5.12.0 2025-02-25 09:42:31 -08:00
3a1ad6ae66
Bumped minimum Kotlin version to 1.9.25 2025-01-27 13:17:17 -08:00
8dda26e7ef
Version 1.0.5-SNAPSHOT 2025-01-27 13:16:50 -08:00
00299f685c
Bumped Kotlin to version 2.1.10 2025-01-27 12:04:42 -08:00
b59f53ba8a
Bumped AssertJ to version 3.27.3 2025-01-27 12:02:27 -08:00
21744cf2c8
Bumped artifacts actions to latest versions 2025-01-27 12:01:14 -08:00
e1eb395012
Version 1.0.4 2025-01-14 11:49:10 -08:00
5d66266fa9
Bumped bld-exec extension to version 1.0.4 2025-01-13 21:41:44 -08:00
316390264e
Fixed BaseProjectBlueprint initialization in tests 2025-01-13 21:28:24 -08:00
3d87280f9c
Updated copyright for 2025 2025-01-13 08:22:01 -08:00
0f6d190cc6
Bumped bld to version 2.2.0 2025-01-13 08:20:59 -08:00
325599575c
Bumped AssertJ to version 3.27.2 2025-01-13 08:20:00 -08:00
86d7351fec
Bumped PMD extension to version 1.1.9 2024-12-28 18:02:20 -08:00
0572b64aed
Bumped AssertJ to version 3.27.0 2024-12-28 18:02:00 -08:00
454ca22536
Bumped JUnit to version 5.11.4 2024-12-28 18:01:31 -08:00
fb793e254a
Version 1.0.3 2024-11-28 10:58:51 -08:00
d658bcf0c4
Enabled verbose compiling 2024-11-28 10:46:10 -08:00
fbaa0264e1
Added support for the -Wextra cli parameter 2024-11-28 10:44:59 -08:00
53df02fa71
Don't use $KOTLIN_HOME if already manually set 2024-11-28 10:43:55 -08:00
6305dd3de4
Bumped Kotlin to version 2.1.0 2024-11-27 19:33:25 -08:00
fe46c87334
Updated dependencies
Bumped JUnit version to 5.11.3
Bumped PMD extension version to 1.1.7
Bumped JDK to version 23 (GitHub CI Workflow)
2024-10-27 16:58:52 -07:00
0aea2095cc
Updated dependencies
Bumped Kotlin to version 2.0.21
Bumped JUnit to version 5.11.2
Bumped PMD extension to version 1.1.6
2024-10-10 13:15:11 -07:00
28 changed files with 758 additions and 193 deletions

View file

@ -2,17 +2,15 @@ name: bld-ci
on: [ push, pull_request, workflow_dispatch ] on: [ push, pull_request, workflow_dispatch ]
env:
KOTLIN_HOME: /usr/share/kotlinc
jobs: jobs:
build-bld-project: build-bld-project:
runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
java-version: [ 17, 21, 22 ] java-version: [ 17, 21, 24 ]
kotlin-version: [ 1.9.24, 2.0.0 ] kotlin-version: [ 1.9.25, 2.0.21, 2.1.20 ]
os: [ ubuntu-latest, windows-latest, macos-latest ]
runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout source repository - name: Checkout source repository
@ -38,4 +36,4 @@ jobs:
run: ./bld download run: ./bld download
- name: Run tests - name: Run tests
run: ./bld compile test run: ./bld compile test

View file

@ -47,11 +47,11 @@ jobs:
uses: actions/configure-pages@v3 uses: actions/configure-pages@v3
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v1 uses: actions/upload-pages-artifact@v3
with: with:
# Upload generated Javadocs repository # Upload generated Javadocs repository
path: "build/javadoc/" path: "build/javadoc/"
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v1 uses: actions/deploy-pages@v4

13
.idea/icon.svg generated Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 179 108" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-210.511,-96.3382)">
<g transform="matrix(1,0,0,1,-23.3386,-649.816)">
<g transform="matrix(0.221288,0,0,0.24,73.9536,390.254)">
<path d="M722.568,1482.92L722.568,1921.1L808.968,1921.1L808.968,1888.7C822.168,1907.9 846.168,1930.1 893.568,1930.1C933.168,1930.1 961.968,1917.5 985.368,1893.5C1012.97,1865.9 1027.37,1827.5 1027.37,1786.1C1027.37,1741.7 1011.17,1705.1 985.368,1680.5C961.968,1658.3 928.968,1644.5 892.368,1644.5C862.968,1644.5 830.568,1654.1 808.968,1683.5L808.968,1482.92L722.568,1482.92ZM871.368,1718.9C888.768,1718.9 903.768,1723.7 917.568,1736.9C930.168,1748.9 938.568,1766.3 938.568,1787.9C938.568,1807.7 930.168,1825.1 917.568,1837.1C904.368,1849.7 887.568,1855.7 872.568,1855.7C856.368,1855.7 837.168,1849.1 823.368,1835.9C813.168,1826.3 803.568,1810.1 803.568,1787.9C803.568,1765.1 812.568,1749.5 822.768,1738.7C836.568,1724.3 852.768,1718.9 871.368,1718.9Z" style="fill:rgb(35,146,255);fill-rule:nonzero;"/>
<rect x="1083.77" y="1482.92" width="86.4" height="438.182" style="fill:rgb(250,144,82);fill-rule:nonzero;"/>
<path d="M1531.37,1482.92L1444.97,1482.92L1444.97,1683.5C1423.37,1654.1 1390.97,1644.5 1361.57,1644.5C1324.97,1644.5 1291.97,1658.3 1268.57,1680.5C1242.77,1705.1 1226.57,1741.7 1226.57,1786.1C1226.57,1827.5 1240.97,1865.9 1268.57,1893.5C1291.97,1917.5 1320.77,1930.1 1360.37,1930.1C1407.77,1930.1 1431.77,1907.9 1444.97,1888.7L1444.97,1921.1L1531.37,1921.1L1531.37,1482.92ZM1382.57,1718.9C1401.17,1718.9 1417.37,1724.3 1431.17,1738.7C1441.37,1749.5 1450.37,1765.1 1450.37,1787.9C1450.37,1810.1 1440.77,1826.3 1430.57,1835.9C1416.77,1849.1 1397.57,1855.7 1381.37,1855.7C1366.37,1855.7 1349.57,1849.7 1336.37,1837.1C1323.77,1825.1 1315.37,1807.7 1315.37,1787.9C1315.37,1766.3 1323.77,1748.9 1336.37,1736.9C1350.17,1723.7 1365.17,1718.9 1382.57,1718.9Z" style="fill:rgb(35,146,255);fill-rule:nonzero;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -2,12 +2,12 @@
<library name="bld"> <library name="bld">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.1.0.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1.jar!/" />
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.bld/dist/bld-2.1.0-sources.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1-sources.jar!/" />
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
</SOURCES> </SOURCES>
<excluded> <excluded>

3
.idea/misc.xml generated
View file

@ -9,10 +9,13 @@
<entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin NOARG" /> <entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin NOARG" />
<entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin POWER_ASSERT" /> <entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin POWER_ASSERT" />
<entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin SAM_WITH_RECEIVER" /> <entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin SAM_WITH_RECEIVER" />
<entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin COMPOSE" />
<entry_point TYPE="field" FQNAME="rife.bld.extension.kotlin.CompilerPlugin KOTLIN_IMPORTS_DUMPER" />
</entry_points> </entry_points>
<pattern value="rife.bld.extension.CompileKotlinOperationBuild" method="pmd" /> <pattern value="rife.bld.extension.CompileKotlinOperationBuild" method="pmd" />
<pattern value="rife.bld.extension.kotlin.CompilerPlugin" /> <pattern value="rife.bld.extension.kotlin.CompilerPlugin" />
<pattern value="rife.bld.extension.kotlin.CompilerPlugin" method="CompilerPlugin" /> <pattern value="rife.bld.extension.kotlin.CompilerPlugin" method="CompilerPlugin" />
<pattern value="rife.bld.extension.CompileKotlinOperationBuild" method="publishGitHub" />
</component> </component>
<component name="PDMPlugin"> <component name="PDMPlugin">
<option name="customRuleSets"> <option name="customRuleSets">

View file

@ -1,9 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Tests" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="rife.bld.extension.CompileKotlinOperationTest" />
<module name="app" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View file

@ -9,7 +9,7 @@
], ],
"java.configuration.updateBuildConfiguration": "automatic", "java.configuration.updateBuildConfiguration": "automatic",
"java.project.referencedLibraries": [ "java.project.referencedLibraries": [
"${HOME}/.bld/dist/bld-2.1.0.jar", "${HOME}/.bld/dist/bld-2.2.1.jar",
"lib/**/*.jar" "lib/**/*.jar"
] ]
} }

View file

@ -2,19 +2,23 @@
[![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) [![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![Kotlin](https://img.shields.io/badge/kotlin-1.9.24%2B-7f52ff.svg)](https://kotlinlang.org) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.25%2B-7f52ff.svg)](https://kotlinlang.org)
[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![Release](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/releases/com/uwyn/rife2/bld-kotlin/maven-metadata.xml?color=blue)](https://repo.rife2.com/#/releases/com/uwyn/rife2/bld-kotlin) [![Release](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/releases/com/uwyn/rife2/bld-kotlin/maven-metadata.xml?color=blue)](https://repo.rife2.com/#/releases/com/uwyn/rife2/bld-kotlin)
[![Snapshot](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/snapshots/com/uwyn/rife2/bld-kotlin/maven-metadata.xml?label=snapshot)](https://repo.rife2.com/#/snapshots/com/uwyn/rife2/bld-kotlin) [![Snapshot](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/snapshots/com/uwyn/rife2/bld-kotlin/maven-metadata.xml?label=snapshot)](https://repo.rife2.com/#/snapshots/com/uwyn/rife2/bld-kotlin)
[![GitHub CI](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml) [![GitHub CI](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml)
To install, please refer to the [extensions](https://github.com/rife2/bld/wiki/Extensions) To install the latest version, add the following to the `lib/bld/bld-wrapper.properties` file:
and [support](https://github.com/rife2/bld/wiki/Kotlin-Support)
documentation. ```properties
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin
```
For more information, please refer to the [extensions](https://github.com/rife2/bld/wiki/Extensions) and [support](https://github.com/rife2/bld/wiki/Kotlin-Support) documentation.
## Compile Kotlin Source Code ## Compile Kotlin Source Code
To compile the source code located in `src/main/kotlin` and `src/test/kotlin` from the current project: To compile the source code located in `src/main/kotlin` and `src/test/kotlin` from the current project add the following to the build file:
```java ```java
@ -40,6 +44,15 @@ for all available configuration options.
Please make sure the Kotlin compiler is [installed](https://kotlinlang.org/docs/command-line.html#install-the-compiler). Please make sure the Kotlin compiler is [installed](https://kotlinlang.org/docs/command-line.html#install-the-compiler).
The extension will look in common locations such as:
- `KOTLIN_HOME`
- `PATH`
- [SDKMAN!](https://sdkman.io/)
- [Homebrew](https://brew.sh/)
- [JetBrains Toolbox](https://www.jetbrains.com/toolbox-app/) (IntelliJ IDEA, Android Studio)
- etc.
You can also manually configure the Kotlin home location as follows: You can also manually configure the Kotlin home location as follows:
```java ```java
@ -66,7 +79,7 @@ public void compile() throws Exception {
} }
``` ```
While older version of Kotlin are likely working with the extension, only version 1.9.24 or higher are officially While older version of Kotlin are likely working with the extension, only version 1.9.25 or higher are officially
supported. supported.
## Template Project ## Template Project

View file

@ -7,9 +7,9 @@
<!-- BEST PRACTICES --> <!-- BEST PRACTICES -->
<rule ref="category/java/bestpractices.xml"> <rule ref="category/java/bestpractices.xml">
<exclude name="AvoidPrintStackTrace"/> <exclude name="AvoidPrintStackTrace"/>
<exclude name="JUnit4TestShouldUseTestAnnotation"/>
<exclude name="JUnitTestContainsTooManyAsserts"/>
<exclude name="GuardLogStatement"/> <exclude name="GuardLogStatement"/>
<exclude name="UnitTestContainsTooManyAsserts"/>
<exclude name="UnitTestShouldUseTestAnnotation"/>
</rule> </rule>
<rule ref="category/java/bestpractices.xml/MissingOverride"> <rule ref="category/java/bestpractices.xml/MissingOverride">

View file

@ -2,12 +2,12 @@
<library name="bld"> <library name="bld">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.1.0.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.1.0-sources.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1-sources.jar!/" />
</SOURCES> </SOURCES>
<excluded> <excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />

View file

@ -9,7 +9,7 @@
], ],
"java.configuration.updateBuildConfiguration": "automatic", "java.configuration.updateBuildConfiguration": "automatic",
"java.project.referencedLibraries": [ "java.project.referencedLibraries": [
"${HOME}/.bld/dist/bld-2.1.0.jar", "${HOME}/.bld/dist/bld-2.2.1.jar",
"lib/**/*.jar" "lib/**/*.jar"
] ]
} }

Binary file not shown.

View file

@ -1,7 +1,7 @@
bld.downloadExtensionJavadoc=false bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true bld.downloadExtensionSources=true
bld.downloadLocation= bld.downloadLocation=
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.2 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.sourceDirectories= bld.sourceDirectories=
bld.version=2.1.0 bld.version=2.2.1

View file

@ -3,6 +3,8 @@ package com.example;
import rife.bld.BuildCommand; import rife.bld.BuildCommand;
import rife.bld.Project; import rife.bld.Project;
import rife.bld.extension.CompileKotlinOperation; import rife.bld.extension.CompileKotlinOperation;
import rife.bld.extension.kotlin.CompileOptions;
import rife.bld.extension.kotlin.JvmOptions;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@ -28,13 +30,14 @@ public class ExampleBuild extends Project {
repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, RIFE2_RELEASES); repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, RIFE2_RELEASES);
final var kotlin = version(2, 0, 20); final var kotlin = version(2, 1, 20);
scope(compile) scope(compile)
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)); .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin));
scope(test) scope(test)
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))); .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2)))
.include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 2)));
// Include the Kotlin source directory when creating or publishing sources Java Archives // Include the Kotlin source directory when creating or publishing sources Java Archives
jarSourcesOperation().sourceDirectories(new File(srcMainDirectory(), "kotlin")); jarSourcesOperation().sourceDirectories(new File(srcMainDirectory(), "kotlin"));
@ -59,13 +62,10 @@ public class ExampleBuild extends Project {
public void compile() throws Exception { public void compile() throws Exception {
// The source code located in src/main/kotlin and src/test/kotlin will be compiled // The source code located in src/main/kotlin and src/test/kotlin will be compiled
new CompileKotlinOperation() new CompileKotlinOperation()
.fromProject(this)
// .kotlinHome("path/to/kotlin") // .kotlinHome("path/to/kotlin")
// .kotlinc("path/to/kotlinc") // .kotlinc("path/to/kotlinc")
.compileOptions(new CompileOptions().verbose(true))
.fromProject(this)
.execute(); .execute();
// var op = new CompileKotlinOperation().fromProject(this);
// op.compileOptions().verbose(true);
// op.execute();
} }
} }

Binary file not shown.

View file

@ -3,8 +3,8 @@ bld.downloadExtensionSources=true
bld.downloadLocation= bld.downloadLocation=
bld.javaOptions= bld.javaOptions=
bld.javacOptions= bld.javacOptions=
bld.extension-exec=com.uwyn.rife2:bld-exec:1.0.3 bld.extension-exec=com.uwyn.rife2:bld-exec:1.0.5
bld.extension-pmd=com.uwyn.rife2:bld-pmd:1.1.5 bld.extension-pmd=com.uwyn.rife2:bld-pmd:1.2.2
bld.repositories=MAVEN_CENTRAL,MAVEN_LOCAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.repositories=MAVEN_CENTRAL,MAVEN_LOCAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.sourceDirectories= bld.sourceDirectories=
bld.version=2.1.0 bld.version=2.2.1

View file

@ -4,7 +4,7 @@ new=/tmp/checkcliargs-new
old=/tmp/checkcliargs-old old=/tmp/checkcliargs-old
kotlinc -h 2>$new kotlinc -h 2>$new
~/.sdkman/candidates/kotlin/2.0.0/bin/kotlinc -h 2>$old ~/.sdkman/candidates/kotlin/2.1.10/bin/kotlinc -h 2>$old
code --diff --wait $old $new code --diff --wait $old $new

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2024 the original author or authors. * Copyright 2023-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import rife.bld.publish.PublishLicense;
import rife.bld.publish.PublishScm; import rife.bld.publish.PublishScm;
import java.util.List; import java.util.List;
import java.util.Locale;
import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.compile; import static rife.bld.dependencies.Scope.compile;
@ -33,7 +34,7 @@ public class CompileKotlinOperationBuild extends Project {
public CompileKotlinOperationBuild() { public CompileKotlinOperationBuild() {
pkg = "rife.bld.extension"; pkg = "rife.bld.extension";
name = "bld-kotlin"; name = "bld-kotlin";
version = version(1, 0, 2); version = version(1, 1, 0, "SNAPSHOT");
javaRelease = 17; javaRelease = 17;
@ -43,11 +44,11 @@ public class CompileKotlinOperationBuild extends Project {
repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, RIFE2_RELEASES, RIFE2_SNAPSHOTS); repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, RIFE2_RELEASES, RIFE2_SNAPSHOTS);
scope(compile) scope(compile)
.include(dependency("com.uwyn.rife2", "bld", version(2, 1, 0))); .include(dependency("com.uwyn.rife2", "bld", version(2, 2, 1)));
scope(test) scope(test)
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2)))
.include(dependency("org.assertj", "assertj-core", version(3, 26, 3))); .include(dependency("org.assertj", "assertj-core", version(3, 27, 3)));
javadocOperation() javadocOperation()
.javadocOptions() .javadocOptions()
@ -97,10 +98,13 @@ public class CompileKotlinOperationBuild extends Project {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
new ExecOperation() var os = System.getProperty("os.name");
.fromProject(this) if (os != null && os.toLowerCase(Locale.US).contains("linux")) {
.command("scripts/cliargs.sh") new ExecOperation()
.execute(); .fromProject(this)
.command("scripts/cliargs.sh")
.execute();
}
super.test(); super.test();
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2024 the original author or authors. * Copyright 2023-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,16 +19,16 @@ package rife.bld.extension;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.extension.kotlin.CompileOptions; import rife.bld.extension.kotlin.CompileOptions;
import rife.bld.extension.kotlin.CompilerPlugin; import rife.bld.extension.kotlin.CompilerPlugin;
import rife.bld.extension.kotlin.JvmOptions;
import rife.bld.operations.AbstractOperation; import rife.bld.operations.AbstractOperation;
import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.operations.exceptions.ExitStatusException;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -40,8 +40,12 @@ import java.util.logging.Logger;
*/ */
public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOperation> { public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOperation> {
private static final Logger LOGGER = Logger.getLogger(CompileKotlinOperation.class.getName()); private static final Logger LOGGER = Logger.getLogger(CompileKotlinOperation.class.getName());
private static final String OS_NAME =
System.getProperty("os.name") != null ? System.getProperty("os.name").toLowerCase(Locale.US) : null;
private static final String KOTLINC_EXECUTABLE = "kotlinc" + (isWindows() ? ".bat" : "");
private final Collection<String> compileMainClasspath_ = new ArrayList<>(); private final Collection<String> compileMainClasspath_ = new ArrayList<>();
private final Collection<String> compileTestClasspath_ = new ArrayList<>(); private final Collection<String> compileTestClasspath_ = new ArrayList<>();
private final JvmOptions jvmOptions_ = new JvmOptions();
private final Collection<File> mainSourceDirectories_ = new ArrayList<>(); private final Collection<File> mainSourceDirectories_ = new ArrayList<>();
private final Collection<File> mainSourceFiles_ = new ArrayList<>(); private final Collection<File> mainSourceFiles_ = new ArrayList<>();
private final Collection<String> plugins_ = new ArrayList<>(); private final Collection<String> plugins_ = new ArrayList<>();
@ -55,6 +59,184 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
private BaseProject project_; private BaseProject project_;
private File workDir_; private File workDir_;
private static String findKotlincInDir(String directory) {
var kotlinc = new File(directory, KOTLINC_EXECUTABLE);
if (isExecutable(kotlinc)) {
return kotlinc.getAbsolutePath();
}
// Check bin subdirectory if it exists
var binDir = new File(directory, "bin");
if (binDir.isDirectory()) {
kotlinc = new File(binDir, KOTLINC_EXECUTABLE);
if (isExecutable(kotlinc)) {
return kotlinc.getAbsolutePath();
}
}
return null;
}
/**
* Locates the Kotlin compiler (kotlinc) executable.
*
* @return The path to the kotlinc executable, or {@code kotlinc}/{@code kotlinc.bat} if not found.
* @since 1.1.0
*/
public static String findKotlincPath() {
return findKotlincPath(false);
}
/**
* Locates the Kotlin compiler (kotlinc) executable.
*
* @param isSilent do not log the path to the kotlinc executable, if {@code true}
* @return The path to the kotlinc executable, or {@code kotlinc}/{@code kotlinc.bat} if not found.
* @since 1.1.0
*/
public static String findKotlincPath(boolean isSilent) {
String kotlincPath;
// Check KOTLIN_HOME environment variable first
var kotlinHome = System.getenv("KOTLIN_HOME");
if (kotlinHome != null && !kotlinHome.isEmpty()) {
kotlincPath = findKotlincInDir(kotlinHome);
if (kotlincPath != null) {
logKotlincPath(kotlincPath, isSilent, "KOTLIN_HOME");
return kotlincPath;
}
}
// Check PATH environment variable
var pathEnv = System.getenv("PATH");
if (pathEnv != null && !pathEnv.isEmpty()) {
var pathDirs = pathEnv.split(File.pathSeparator);
for (var dir : pathDirs) {
kotlincPath = findKotlincInDir(dir);
if (kotlincPath != null) {
logKotlincPath(kotlincPath, isSilent, "PATH");
return kotlincPath;
}
}
}
// Common installation paths (e.g., SDKMAN!, IntelliJ IDEA, etc.)
var commonPaths = new LinkedHashMap<String, String>();
if (isLinux()) {
var userHome = System.getProperty("user.home");
if (userHome != null) {
commonPaths.put(userHome + "/.sdkman/candidates/kotlin/current/bin", "SDKMAN!");
}
commonPaths.put("/snap/bin", "Kotlin (Snap)");
commonPaths.put("/usr/bin", null);
commonPaths.put("/usr/share", null);
commonPaths.put("/usr/local/bin", null);
commonPaths.put("/usr/local/kotlin/bin", null);
commonPaths.put("/usr/share/kotlin/bin/", null);
commonPaths.put("/opt/kotlin/bin", null);
if (userHome != null) {
commonPaths.put(userHome + "/.local/share/JetBrains/Toolbox/apps/intellij-idea-ultimate/plugins/Kotlin/kotlinc/bin",
"IntelliJ IDEA Ultimate");
commonPaths.put(userHome + "/.local/share/JetBrains/Toolbox/apps/intellij-idea-community-edition/plugins/Kotlin/kotlinc/bin",
"IntelliJ IDEA Community Edition");
commonPaths.put(userHome + "/.local/share/JetBrains/Toolbox/apps/android-studio/plugins/Kotlin/kotlinc/bin",
"Android Studio");
}
commonPaths.put("/snap/intellij-idea-ultimate/current/commons/plugins/Kotlin/kotlinc/bin",
"IntelliJ IDEA Ultimate (Snap)");
commonPaths.put("/snap/intellij-idea-community/current/commons/plugins/Kotlin/kotlinc/bin",
"IntelliJ IDEA Community Edition (Snap)");
commonPaths.put("/snap/android-studio/current/android-studio/commons/plugins/Kotlin/kotlinc/bin",
"Android Studio (Snap)");
} else if (isWindows()) {
commonPaths.put("C:\\tools\\kotlinc\\bin", null);
var localAppData = System.getenv("LOCALAPPDATA");
if (localAppData != null) {
commonPaths.put(localAppData + "\\Programs\\IntelliJ IDEA Ultimate\\plugins\\Kotlin\\kotlinc\\bin",
"IntelliJ IDEA Ultimate");
commonPaths.put(localAppData + "\\Programs\\IntelliJ IDEA Community Edition\\plugins\\Kotlin\\kotlinc\\bin",
"IntelliJ IDEA Community Edition");
commonPaths.put(localAppData + "\\Programs\\Android Studio\\plugins\\Kotlin\\kotlinc\\bin",
"Android Studio");
}
var programFiles = System.getenv("ProgramFiles");
if (programFiles != null) {
commonPaths.put(programFiles + "\\Kotlin\\bin", null);
}
} else if (isMacOS()) {
var userHome = System.getProperty("user.home");
if (userHome != null) {
commonPaths.put(userHome + "/.sdkman/candidates/kotlin/current/bin", "SDKMAN!");
}
commonPaths.put("/opt/homebrew/bin", "Homebrew");
commonPaths.put("/usr/local/bin", null);
commonPaths.put("/Applications/IntelliJ IDEA.app/Contents/plugins/Kotlin/kotlinc/bin/",
"IntelliJ IDEA");
commonPaths.put("/Applications/IntelliJ IDEA Community Edition.app/Contents/plugins/Kotlin/kotlinc/bin/",
"IntelliJ IDEA Community Edition");
commonPaths.put("/Applications/Android Studio.app/Contents/plugins/Kotlin/kotlinc/bin",
"Android Studio");
}
for (var path : commonPaths.keySet()) {
kotlincPath = findKotlincInDir(path);
if (kotlincPath != null) {
logKotlincPath(kotlincPath, isSilent, commonPaths.get(path));
return kotlincPath;
}
}
// Try 'which' or 'where' commands (less reliable but sometimes works)
try {
Process process;
if (isWindows()) {
process = Runtime.getRuntime().exec("where kotlinc");
} else {
process = Runtime.getRuntime().exec("which kotlinc");
}
try (var scanner = new Scanner(process.getInputStream())) {
if (scanner.hasNextLine()) {
kotlincPath = scanner.nextLine().trim();
if (isExecutable(new File(kotlincPath))) {
logKotlincPath(kotlincPath, isSilent);
return kotlincPath;
}
}
}
} catch (Exception ignored) {
// Ignore exceptions from which/where, as they might not be available
}
return KOTLINC_EXECUTABLE;
}
private static boolean isExecutable(File file) {
return file != null && file.exists() && file.isFile() && file.canExecute();
}
/**
* Determines if the operating system is Linux.
*
* @return true if the operating system is Linux, false otherwise.
* @since 1.1.0
*/
public static boolean isLinux() {
return OS_NAME != null && (OS_NAME.contains("linux") || OS_NAME.contains("unix")); // Consider Unix-like systems as well.
}
/**
* Determines if the current operating system is macOS.
*
* @return true if the OS is macOS, false otherwise.
* @since 1.1.0
*/
public static boolean isMacOS() {
return OS_NAME != null && (OS_NAME.contains("mac") || OS_NAME.contains("darwin") || OS_NAME.contains("osx"));
}
/** /**
* Determines if the given string is not blank. * Determines if the given string is not blank.
* *
@ -65,6 +247,30 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
return s != null && !s.isBlank(); return s != null && !s.isBlank();
} }
/**
* Determines if the current operating system is Windows.
*
* @return true if the operating system is Windows, false otherwise.
* @since 1.1.0
*/
public static boolean isWindows() {
return OS_NAME != null && OS_NAME.contains("win");
}
private static void logKotlincPath(String kotlincPath, boolean isSilent) {
logKotlincPath(kotlincPath, isSilent, null);
}
private static void logKotlincPath(String kotlincPath, boolean isSilent, String from) {
if (LOGGER.isLoggable(Level.INFO) && !isSilent) {
if (from != null) {
LOGGER.info("Using Kotlin compiler inferred from " + from + ": " + kotlincPath);
} else {
LOGGER.info("Using Kotlin compiler found at: " + kotlincPath);
}
}
}
/** /**
* Provides the main build destination directory. * Provides the main build destination directory.
* *
@ -145,6 +351,17 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
return buildTestDirectory_; return buildTestDirectory_;
} }
private String cleanPath(File path) {
return cleanPath(path.getAbsolutePath());
}
private String cleanPath(String path) {
if (isWindows()) {
return path.replaceAll("\\\\", "\\\\\\\\");
}
return path;
}
/** /**
* Provides entries for the main compilation classpath. * Provides entries for the main compilation classpath.
* *
@ -284,6 +501,12 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
protected void executeBuildSources(Collection<String> classpath, Collection<File> sources, File destination, protected void executeBuildSources(Collection<String> classpath, Collection<File> sources, File destination,
File friendPaths) File friendPaths)
throws ExitStatusException { throws ExitStatusException {
var cp = new ArrayList<String>();
if (classpath != null && !classpath.isEmpty()) {
cp.addAll(classpath);
}
if (sources.isEmpty()) { if (sources.isEmpty()) {
if (!silent() && LOGGER.isLoggable(Level.WARNING)) { if (!silent() && LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("Nothing to compile."); LOGGER.warning("Nothing to compile.");
@ -296,49 +519,84 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE); throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
} }
var command = new ArrayList<String>();
var args = new ArrayList<String>(); var args = new ArrayList<String>();
// kotlinc // kotlinc
args.add(kotlinCompiler()); if (kotlinc_ != null) {
command.add(kotlinc_.getAbsolutePath());
} else if (kotlinHome_ != null) {
var kotlinc = findKotlincInDir(kotlinHome_.getAbsolutePath());
if (kotlinc != null) {
command.add(kotlinc);
} else {
if (LOGGER.isLoggable(Level.SEVERE) && !silent()) {
LOGGER.severe("Could not locate Kotlin compiler in: " + kotlinHome_);
}
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
}
} else {
command.add(findKotlincPath(silent()));
}
// JVM options
if (!jvmOptions_.isEmpty()) {
jvmOptions_.forEach(s -> command.add("-J" + s));
}
// classpath // classpath
if (classpath != null && !classpath.isEmpty()) { if (compileOptions_ != null && !compileOptions_.classpath().isEmpty()) {
cp.addAll(compileOptions_.classpath().stream().map(this::cleanPath).toList());
}
if (!cp.isEmpty()) {
args.add("-cp"); args.add("-cp");
args.add(FileUtils.joinPaths(classpath.stream().toList())); args.add('"' + FileUtils.joinPaths(cp.stream().map(this::cleanPath).toList()) + '"');
}
// compile options
if (compileOptions_ != null && !compileOptions_.args().isEmpty()) {
args.addAll(compileOptions_.args());
} }
// destination // destination
args.add("-d"); args.add("-d");
args.add(destination.getAbsolutePath()); args.add('"' + cleanPath(destination) + '"');
// friend-path // friend-path
if (friendPaths != null && friendPaths.exists()) { if (friendPaths != null && friendPaths.exists()) {
args.add("-Xfriend-paths=" + friendPaths.getAbsolutePath()); args.add("-Xfriend-paths=\"" + cleanPath(friendPaths) + '"');
}
// options
if (compileOptions_ != null) {
args.addAll(compileOptions_.args());
} }
// plugins // plugins
if (!plugins_.isEmpty()) { if (!plugins_.isEmpty()) {
plugins_.forEach(p -> args.add("-Xplugin=" + p)); plugins_.forEach(p -> args.add("-Xplugin=\"" + cleanPath(p) + '"'));
} }
// sources // sources
sources.forEach(f -> args.add(f.getAbsolutePath())); sources.forEach(f -> args.add('"' + cleanPath(f) + '"'));
var argsLine = String.join(" ", args);
// log the command line
if (LOGGER.isLoggable(Level.FINE) && !silent()) { if (LOGGER.isLoggable(Level.FINE) && !silent()) {
LOGGER.fine(String.join(" ", args)); LOGGER.fine(String.join(" ", command) + " " + argsLine);
} }
var pb = new ProcessBuilder();
pb.inheritIO();
pb.command(args);
pb.directory(workDir_);
try { try {
// create and write the @argfile
var argsFile = File.createTempFile("bld-kotlinc-", ".args");
argsFile.deleteOnExit();
Files.write(argsFile.toPath(), argsLine.getBytes());
command.add("@" + argsFile.getAbsolutePath());
// run the command
var pb = new ProcessBuilder();
pb.inheritIO();
pb.command(command);
pb.directory(workDir_);
var proc = pb.start(); var proc = pb.start();
proc.waitFor(); proc.waitFor();
ExitStatusException.throwOnFailure(proc.exitValue()); ExitStatusException.throwOnFailure(proc.exitValue());
@ -374,19 +632,41 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
*/ */
protected void executeCreateBuildDirectories() throws IOException { protected void executeCreateBuildDirectories() throws IOException {
if (buildMainDirectory() != null && !buildMainDirectory().exists() && !buildMainDirectory().mkdirs()) { if (buildMainDirectory() != null && !buildMainDirectory().exists() && !buildMainDirectory().mkdirs()) {
throw new IOException("Could not created build main directory: " + buildMainDirectory().getAbsolutePath()); throw new IOException("Could not create build main directory: " + buildMainDirectory().getAbsolutePath());
} }
if (buildTestDirectory() != null && !buildTestDirectory().exists() && !buildTestDirectory().mkdirs()) { if (buildTestDirectory() != null && !buildTestDirectory().exists() && !buildTestDirectory().mkdirs()) {
throw new IOException("Could not created build test directory: " + buildTestDirectory().getAbsolutePath()); throw new IOException("Could not create build test directory: " + buildTestDirectory().getAbsolutePath());
} }
} }
private File findKotlinHome() {
// Deduct from kotlinc location if provided
if (kotlinc_ != null) {
var parent = kotlinc_.getParentFile();
if (parent != null && parent.isDirectory()) {
if (parent.getPath().endsWith("bin")) {
if (parent.getParentFile() != null && parent.getParentFile().isDirectory()) {
return parent.getParentFile();
}
} else {
return parent;
}
}
} else {
var kotlinHome = System.getenv("KOTLIN_HOME");
if (kotlinHome != null) {
return new File(kotlinHome);
}
}
return null;
}
/** /**
* Configures a compile operation from a {@link BaseProject}. * Configures a compile operation from a {@link BaseProject}.
* <p> * <p>
* Sets the following from the project: * Sets the following from the project:
* <ul> * <ul>
* <li>{@link #kotlinHome() kotlinHome} to the {@code KOTLIN_HOME} environment variable, if set.</li>
* <li>{@link #workDir() workDir} to the project's directory.</li> * <li>{@link #workDir() workDir} to the project's directory.</li>
* <li>{@link #buildMainDirectory() buildMainDirectory}</li> * <li>{@link #buildMainDirectory() buildMainDirectory}</li>
* <li>{@link #buildTestDirectory() buildTestDirectory}</li> * <li>{@link #buildTestDirectory() buildTestDirectory}</li>
@ -405,12 +685,6 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
*/ */
public CompileKotlinOperation fromProject(BaseProject project) { public CompileKotlinOperation fromProject(BaseProject project) {
project_ = project; project_ = project;
var env = System.getenv("KOTLIN_HOME");
if (env != null) {
kotlinHome_ = new File(env);
}
workDir_ = new File(project.workDirectory().getAbsolutePath()); workDir_ = new File(project.workDirectory().getAbsolutePath());
var op = buildMainDirectory(project.buildMainDirectory()) var op = buildMainDirectory(project.buildMainDirectory())
@ -435,16 +709,34 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
return op; return op;
} }
private String kotlinCompiler() { /**
if (kotlinc_ != null) { * Retrieves the Java Virtual Machine options.
return kotlinc_.getAbsolutePath(); *
} else if (kotlinHome_ != null) { * @return the JVM options
var kotlinc = Path.of(kotlinHome_.getAbsolutePath(), "bin", "kotlinc").toFile(); */
if (kotlinc.exists() && kotlinc.canExecute()) { public JvmOptions jvmOptions() {
return kotlinc.getAbsolutePath(); return jvmOptions_;
} }
}
return "kotlinc"; /**
* Pass an option directly to the Java Virtual Machine
*
* @param jvmOptions the JVM options
* @return this operation instance
*/
public CompileKotlinOperation jvmOptions(Collection<String> jvmOptions) {
jvmOptions_.addAll(jvmOptions);
return this;
}
/**
* Pass an option directly to the Java Virtual Machine
*
* @param jvmOptions one or more JVM option
* @return this operation instance
*/
public CompileKotlinOperation jvmOptions(String... jvmOptions) {
return jvmOptions(List.of(jvmOptions));
} }
/** /**
@ -753,15 +1045,17 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
* @see #plugins(File, CompilerPlugin...) * @see #plugins(File, CompilerPlugin...)
*/ */
public CompileKotlinOperation plugins(CompilerPlugin... plugins) { public CompileKotlinOperation plugins(CompilerPlugin... plugins) {
if (kotlinHome_ != null) { var kotlinHome = kotlinHome_;
var kotlinLib = new File(kotlinHome_, "lib"); if (kotlinHome == null) {
kotlinHome = findKotlinHome();
}
if (kotlinHome != null) {
var kotlinLib = new File(kotlinHome, "lib");
for (var plugin : plugins) { for (var plugin : plugins) {
plugins(kotlinLib, plugin); plugins(kotlinLib, plugin);
} }
} else { } else if (LOGGER.isLoggable(Level.WARNING) && !silent()) {
if (LOGGER.isLoggable(Level.WARNING) && !silent()) { LOGGER.warning("The Kotlin home must be set (or discovered) to specify compiler plugins directly.");
LOGGER.warning("The Kotlin home must be set to specify compiler plugins directly.");
}
} }
return this; return this;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2024 the original author or authors. * Copyright 2023-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,13 +17,18 @@
package rife.bld.extension.kotlin; package rife.bld.extension.kotlin;
import rife.bld.extension.CompileKotlinOperation; import rife.bld.extension.CompileKotlinOperation;
import rife.bld.operations.AbstractToolProviderOperation;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.logging.Level;
import java.util.logging.Logger;
import static rife.bld.extension.CompileKotlinOperation.isNotBlank; import static rife.bld.extension.CompileKotlinOperation.isNotBlank;
@ -34,10 +39,10 @@ import static rife.bld.extension.CompileKotlinOperation.isNotBlank;
* @since 1.0 * @since 1.0
*/ */
public class CompileOptions { public class CompileOptions {
private static final Logger LOGGER = Logger.getLogger(CompileOptions.class.getName());
private final Collection<String> advancedOptions_ = new ArrayList<>(); private final Collection<String> advancedOptions_ = new ArrayList<>();
private final Collection<File> argFile_ = new ArrayList<>(); private final Collection<File> argFile_ = new ArrayList<>();
private final Collection<File> classpath_ = new ArrayList<>(); private final Collection<File> classpath_ = new ArrayList<>();
private final Collection<String> jvmOptions_ = new ArrayList<>();
private final Collection<String> optIn_ = new ArrayList<>(); private final Collection<String> optIn_ = new ArrayList<>();
private final Collection<String> options_ = new ArrayList<>(); private final Collection<String> options_ = new ArrayList<>();
private final Collection<String> plugin_ = new ArrayList<>(); private final Collection<String> plugin_ = new ArrayList<>();
@ -60,6 +65,7 @@ public class CompileOptions {
private boolean progressive_; private boolean progressive_;
private boolean verbose_; private boolean verbose_;
private boolean wError_; private boolean wError_;
private boolean wExtra_;
/** /**
* Specify advanced compiler options. * Specify advanced compiler options.
@ -111,7 +117,6 @@ public class CompileOptions {
return this; return this;
} }
/** /**
* Allow using declarations only from the specified version of Kotlin bundled libraries. * Allow using declarations only from the specified version of Kotlin bundled libraries.
* *
@ -250,13 +255,27 @@ public class CompileOptions {
// @argfile // @argfile
if (!argFile_.isEmpty()) { if (!argFile_.isEmpty()) {
argFile_.forEach(f -> args.add("@" + f.getAbsolutePath())); argFile_.forEach(f -> {
} if (f.exists()) {
try {
// classpath try (var reader = Files.newBufferedReader(f.toPath(), Charset.defaultCharset())) {
if (!classpath_.isEmpty()) { var tokenizer = new AbstractToolProviderOperation.CommandLineTokenizer(reader);
args.add("-classpath"); String token;
args.add(classpath_.stream().map(File::getAbsolutePath).collect(Collectors.joining(File.pathSeparator))); while ((token = tokenizer.nextToken()) != null) {
args.add(token);
}
}
} catch (IOException e) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "Could not read: " + f.getAbsolutePath(), e);
}
}
} else {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("File not found: " + f.getAbsolutePath());
}
}
});
} }
// expression // expression
@ -292,11 +311,6 @@ public class CompileOptions {
args.add("-Xjdk-release=" + jdkRelease_); args.add("-Xjdk-release=" + jdkRelease_);
} }
// JVM options
if (!jvmOptions_.isEmpty()) {
jvmOptions_.forEach(s -> args.add("-J" + s));
}
// kotlin-home // kotlin-home
if (kotlinHome_ != null) { if (kotlinHome_ != null) {
args.add("-kotlin-home"); args.add("-kotlin-home");
@ -379,9 +393,20 @@ public class CompileOptions {
args.add("-Werror"); args.add("-Werror");
} }
// advanced option (X) // Wextra
if (wExtra_) {
args.add("-Wextra");
}
// advanced options (X)
if (!advancedOptions_.isEmpty()) { if (!advancedOptions_.isEmpty()) {
advancedOptions_.forEach(it -> args.add("-X" + it)); advancedOptions_.forEach(it -> {
if (it.startsWith("-X")) {
args.add(it);
} else {
args.add("-X" + it);
}
});
} }
return args; return args;
@ -597,6 +622,15 @@ public class CompileOptions {
return wError_; return wError_;
} }
/**
* Indicates whether additional declaration, expression, and type compiler checks emit warnings.
*
* @return {@code true} or {@code false}
*/
public boolean isWExtra() {
return wExtra_;
}
/** /**
* Generate metadata for Java 1.8 reflection on method parameters. * Generate metadata for Java 1.8 reflection on method parameters.
* *
@ -663,7 +697,7 @@ public class CompileOptions {
* Limit the API of the JDK in the classpath to the specified Java version. Automatically sets * Limit the API of the JDK in the classpath to the specified Java version. Automatically sets
* {@link #jvmTarget(String) JVM target} version. * {@link #jvmTarget(String) JVM target} version.
* <p> * <p>
* Possible values are 1.8, 9, 10, ..., 22. The default value is 1.8. * Possible values are 1.8, 9, 10, ..., 23. The default value is 1.8.
* *
* @param version the target version * @param version the target version
* @return this operation instance * @return this operation instance
@ -678,8 +712,6 @@ public class CompileOptions {
* <p> * <p>
* Limit the API of the JDK in the classpath to the specified Java version. Automatically sets * Limit the API of the JDK in the classpath to the specified Java version. Automatically sets
* {@link #jvmTarget(String) JVM target} version. * {@link #jvmTarget(String) JVM target} version.
* <p>
* Possible values are 1.8, 9, 10, ..., 22. The default value is 1.8.
* *
* @param version the target version * @param version the target version
* @return this operation instance * @return this operation instance
@ -689,36 +721,6 @@ public class CompileOptions {
return jdkRelease(String.valueOf(version)); return jdkRelease(String.valueOf(version));
} }
/**
* Retrieves the Java Virtual Machine options.
*
* @return the JVM options
*/
public Collection<String> jvmOptions() {
return jvmOptions_;
}
/**
* Pass an option directly to Java Virtual Machine
*
* @param jvmOptions the JVM options
* @return this operation instance
*/
public CompileOptions jvmOptions(Collection<String> jvmOptions) {
jvmOptions_.addAll(jvmOptions);
return this;
}
/**
* Pass an option directly to JVM
*
* @param jvmOptions one or more JVM option
* @return this operation instance
*/
public CompileOptions jvmOptions(String... jvmOptions) {
return jvmOptions(List.of(jvmOptions));
}
/** /**
* Specify the target version of the generated JVM bytecode. * Specify the target version of the generated JVM bytecode.
* *
@ -733,7 +735,7 @@ public class CompileOptions {
/** /**
* Specify the target version of the generated JVM bytecode. * Specify the target version of the generated JVM bytecode.
* <p> * <p>
* Possible values are 1.8, 9, 10, ..., 22. The default value is 1.8. * Possible values are 1.8, 9, 10, ..., 23. The default value is 1.8.
* *
* @param target the target version * @param target the target version
* @return this operation instance * @return this operation instance
@ -1071,4 +1073,15 @@ public class CompileOptions {
wError_ = wError; wError_ = wError;
return this; return this;
} }
/**
* Enable additional declaration, expression, and type compiler checks that emit warnings if {@code true}.
*
* @param wExtra {@code true} or {@code false}
* @return this operation instance
*/
public CompileOptions wExtra(boolean wExtra) {
wExtra_ = wExtra;
return this;
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2024 the original author or authors. * Copyright 2023-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package rife.bld.extension.kotlin; package rife.bld.extension.kotlin;
/** /**
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* Defines the known Kotlin compiler plugin JARs. * Defines the known Kotlin compiler plugin JARs.
* *
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a> * @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
@ -25,6 +26,8 @@ package rife.bld.extension.kotlin;
public enum CompilerPlugin { public enum CompilerPlugin {
ALL_OPEN("allopen-compiler-plugin.jar"), ALL_OPEN("allopen-compiler-plugin.jar"),
ASSIGNMENT("assignment-compiler-plugin.jar"), ASSIGNMENT("assignment-compiler-plugin.jar"),
COMPOSE("compose-compiler-plugin.jar"),
KOTLIN_IMPORTS_DUMPER("kotlin-imports-dumper-compiler-plugin.jar"),
KOTLINX_SERIALIZATION("kotlinx-serialization-compiler-plugin.jar"), KOTLINX_SERIALIZATION("kotlinx-serialization-compiler-plugin.jar"),
KOTLIN_SERIALIZATION("kotlin-serialization-compiler-plugin.jar"), KOTLIN_SERIALIZATION("kotlin-serialization-compiler-plugin.jar"),
LOMBOK("lombok-compiler-plugin.jar"), LOMBOK("lombok-compiler-plugin.jar"),

View file

@ -0,0 +1,90 @@
/*
* Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* 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 rife.bld.extension.kotlin;
import rife.tools.StringUtils;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Java Virtual Machine options.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 1.1.0
*/
@SuppressWarnings("PMD.LooseCoupling")
public class JvmOptions extends ArrayList<String> {
/**
* Keyword to enable native access for all code on the class path.
*/
public final static String ALL_UNNAMED = "ALL-UNNAMED";
@Serial
private static final long serialVersionUID = 1L;
/**
* Modules that are permitted to perform restricted native operations.
* The module name can also be {@link #ALL_UNNAMED}.
*
* @param modules the module names
* @return this list of options
*/
public JvmOptions enableNativeAccess(String... modules) {
return enableNativeAccess(List.of(modules));
}
/**
* Modules that are permitted to perform restricted native operations.
* The module name can also be {@link #ALL_UNNAMED}.
*
* @param modules the module names
* @return this list of options
*/
public JvmOptions enableNativeAccess(Collection<String> modules) {
add("--enable-native-access=" + StringUtils.join(modules, ","));
return this;
}
/**
* Controls what action the Java runtime takes when native access is not enabled for a module.
*
* @param access the access mode
* @return this list of options
*/
public JvmOptions illegalNativeAccess(NativeAccess access) {
add("--illegal-native-access=" + access.mode);
return this;
}
/**
* Illegal native access modes.
*/
public enum NativeAccess {
ALLOW("allow"),
DENY("deny"),
WARN("warn");
public final String mode;
NativeAccess(String mode) {
this.mode = mode;
}
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2024 the original author or authors. * Copyright 2023-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import rife.bld.BaseProject;
import rife.bld.blueprints.BaseProjectBlueprint; import rife.bld.blueprints.BaseProjectBlueprint;
import rife.bld.extension.kotlin.CompileOptions; import rife.bld.extension.kotlin.CompileOptions;
import rife.bld.extension.kotlin.CompilerPlugin; import rife.bld.extension.kotlin.CompilerPlugin;
import rife.bld.extension.kotlin.JvmOptions;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import java.io.File; import java.io.File;
@ -30,6 +31,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.logging.ConsoleHandler; import java.util.logging.ConsoleHandler;
import java.util.logging.Level; import java.util.logging.Level;
@ -86,7 +88,7 @@ class CompileKotlinOperationTest {
@Test @Test
void testCollections() { void testCollections() {
var op = new CompileKotlinOperation() var op = new CompileKotlinOperation()
.fromProject(new BaseProjectBlueprint(new File("examples"), "com.example", "Example")) .fromProject(new BaseProjectBlueprint(new File("examples"), "com.example", "Example", "Example"))
.kotlinHome("/kotlin_home") .kotlinHome("/kotlin_home")
.kotlinc("kotlinc") .kotlinc("kotlinc")
.workDir("work_dir") .workDir("work_dir")
@ -103,11 +105,11 @@ class CompileKotlinOperationTest {
.testSourceFiles(List.of(new File("tfile3"), new File("tfile4"))) .testSourceFiles(List.of(new File("tfile3"), new File("tfile4")))
.testSourceFiles(new File("tfile5"), new File("tfile6")) .testSourceFiles(new File("tfile5"), new File("tfile6"))
.plugins("plugin1", "plugin2") .plugins("plugin1", "plugin2")
.plugins(CompilerPlugin.KOTLIN_SERIALIZATION, CompilerPlugin.ASSIGNMENT) .plugins(CompilerPlugin.KOTLIN_SERIALIZATION, CompilerPlugin.ASSIGNMENT, CompilerPlugin.COMPOSE)
.plugins(new File("lib/compile"), CompilerPlugin.LOMBOK, CompilerPlugin.POWER_ASSERT) .plugins(new File("lib/compile"), CompilerPlugin.LOMBOK, CompilerPlugin.POWER_ASSERT)
.plugins(Path.of("lib/compile"), CompilerPlugin.NOARG, CompilerPlugin.ALL_OPEN) .plugins(Path.of("lib/compile"), CompilerPlugin.NOARG, CompilerPlugin.ALL_OPEN,
CompilerPlugin.KOTLIN_IMPORTS_DUMPER)
.plugins("lib/compile", CompilerPlugin.KOTLINX_SERIALIZATION, CompilerPlugin.SAM_WITH_RECEIVER) .plugins("lib/compile", CompilerPlugin.KOTLINX_SERIALIZATION, CompilerPlugin.SAM_WITH_RECEIVER)
.plugins(List.of("plugin3", "plugin4")); .plugins(List.of("plugin3", "plugin4"));
try (var softly = new AutoCloseableSoftAssertions()) { try (var softly = new AutoCloseableSoftAssertions()) {
@ -131,12 +133,14 @@ class CompileKotlinOperationTest {
new File("tfile1"), new File("tfile2"), new File("tfile3"), new File("tfile1"), new File("tfile2"), new File("tfile3"),
new File("tfile4"), new File("tfile5"), new File("tfile6")); new File("tfile4"), new File("tfile5"), new File("tfile6"));
softly.assertThat(op.plugins()).as("plugins").contains("plugin1", "plugin2", "plugin3", "plugin4", softly.assertThat(op.plugins()).as("plugins").contains("plugin1", "plugin2", "plugin3", "plugin4",
"/kotlin_home/lib/kotlin-serialization-compiler-plugin.jar", new File("/kotlin_home/lib/kotlin-serialization-compiler-plugin.jar").getAbsolutePath(),
"/kotlin_home/lib/assignment-compiler-plugin.jar", new File("/kotlin_home/lib/assignment-compiler-plugin.jar").getAbsolutePath(),
new File("/kotlin_home/lib/compose-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "lombok-compiler-plugin.jar").getAbsolutePath(), new File("lib/compile", "lombok-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "power-assert-compiler-plugin.jar").getAbsolutePath(), new File("lib/compile", "power-assert-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "noarg-compiler-plugin.jar").getAbsolutePath(), new File("lib/compile", "noarg-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "allopen-compiler-plugin.jar").getAbsolutePath(), new File("lib/compile", "allopen-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "kotlin-imports-dumper-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "kotlinx-serialization-compiler-plugin.jar").getAbsolutePath(), new File("lib/compile", "kotlinx-serialization-compiler-plugin.jar").getAbsolutePath(),
new File("lib/compile", "sam-with-receiver-compiler-plugin.jar").getAbsolutePath()); new File("lib/compile", "sam-with-receiver-compiler-plugin.jar").getAbsolutePath());
} }
@ -167,8 +171,7 @@ class CompileKotlinOperationTest {
} }
var op = new CompileKotlinOperation() var op = new CompileKotlinOperation()
.fromProject(new BaseProjectBlueprint(new File("examples"), "com.example", .fromProject(new BaseProjectBlueprint(new File("examples"), "com.example", "Example", "Example"))
"Example"))
.buildMainDirectory(mainDir) .buildMainDirectory(mainDir)
.buildTestDirectory(testDir) .buildTestDirectory(testDir)
.compileMainClasspath(compileJars) .compileMainClasspath(compileJars)
@ -177,10 +180,16 @@ class CompileKotlinOperationTest {
.compileTestClasspath(mainDir.getAbsolutePath()); .compileTestClasspath(mainDir.getAbsolutePath());
op.compileOptions().verbose(true); op.compileOptions().verbose(true);
op.compileOptions().jdkRelease("17"); op.compileOptions().argFile("src/test/resources/argfile.txt", "src/test/resources/argfile2.txt");
if (!CompileKotlinOperation.isWindows()) {
op.jvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED);
assertThat(op.jvmOptions()).containsExactly("--enable-native-access=ALL-UNNAMED");
}
var args = op.compileOptions().args(); var args = op.compileOptions().args();
var matches = List.of("-Xjdk-release=17", "-no-stdlib", "-verbose"); var matches = List.of("-Xjdk-release=17", "-no-reflect", "-progressive", "-include-runtime", "-no-stdlib",
"-verbose");
assertThat(args).as(args + " == " + matches).isEqualTo(matches); assertThat(args).as(args + " == " + matches).isEqualTo(matches);
op.execute(); op.execute();
@ -205,14 +214,43 @@ class CompileKotlinOperationTest {
} }
} }
@Test
void testFindKotlincPath() {
assertThat(CompileKotlinOperation.findKotlincPath()).doesNotStartWith("kotlinc");
}
@Test
void testFromProject() {
var examples = new File("examples");
var op = new CompileKotlinOperation().fromProject(
new BaseProjectBlueprint(examples, "com.example", "examples", "examples"));
assertThat(op.mainSourceDirectories()).containsExactly(new File(examples, "src/main/kotlin"));
assertThat(op.testSourceDirectories()).containsExactly(new File(examples, "src/test/kotlin"));
}
@Test @Test
void testFromProjectNoKotlin() { void testFromProjectNoKotlin() {
var op = new CompileKotlinOperation().fromProject( var op = new CompileKotlinOperation().fromProject(
new BaseProjectBlueprint(new File("foo"), "org.example", "foo")); new BaseProjectBlueprint(new File("foo"), "org.example", "foo", "foo"));
assertThat(op.mainSourceDirectories()).isEmpty(); assertThat(op.mainSourceDirectories()).isEmpty();
assertThat(op.testSourceDirectories()).isEmpty(); assertThat(op.testSourceDirectories()).isEmpty();
} }
@Test
void testIsOS() {
var osName = System.getProperty("os.name");
if (osName != null) {
var os = osName.toLowerCase(Locale.US);
if (os.contains("win")) {
assertThat(CompileKotlinOperation.isWindows()).isTrue();
} else if (os.contains("linux") || os.contains("unix")) {
assertThat(CompileKotlinOperation.isLinux()).isTrue();
} else if (os.contains("mac") || os.contains("darwin")) {
assertThat(CompileKotlinOperation.isMacOS()).isTrue();
}
}
}
@Test @Test
void testKotlinHome() { void testKotlinHome() {
var foo = new File("foo"); var foo = new File("foo");
@ -314,6 +352,8 @@ class CompileKotlinOperationTest {
.fromProject(new BaseProject()) .fromProject(new BaseProject())
.plugins(CompilerPlugin.ALL_OPEN, .plugins(CompilerPlugin.ALL_OPEN,
CompilerPlugin.ASSIGNMENT, CompilerPlugin.ASSIGNMENT,
CompilerPlugin.COMPOSE,
CompilerPlugin.KOTLIN_IMPORTS_DUMPER,
CompilerPlugin.KOTLINX_SERIALIZATION, CompilerPlugin.KOTLINX_SERIALIZATION,
CompilerPlugin.KOTLIN_SERIALIZATION, CompilerPlugin.KOTLIN_SERIALIZATION,
CompilerPlugin.LOMBOK, CompilerPlugin.LOMBOK,

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2024 the original author or authors. * Copyright 2023-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,6 +18,8 @@ package rife.bld.extension.kotlin;
import org.assertj.core.api.AutoCloseableSoftAssertions; import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -45,14 +47,11 @@ class CompileOptionsTest {
.collect(Collectors.joining(File.pathSeparator)); .collect(Collectors.joining(File.pathSeparator));
} }
@Test @Test
@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") @SuppressWarnings("PMD.UnitTestShouldIncludeAssert")
void testArgs() { void testArgs() {
var options = new CompileOptions() var options = new CompileOptions()
.apiVersion("11") .apiVersion("11")
.argFile(new File("file.txt"), new File("file2.txt"))
.classpath(new File("path1"), new File("path2"))
.javaParameters(true) .javaParameters(true)
.jvmTarget("11") .jvmTarget("11")
.includeRuntime(true) .includeRuntime(true)
@ -71,12 +70,11 @@ class CompileOptionsTest {
.progressive(true) .progressive(true)
.scriptTemplates("name", "name2") .scriptTemplates("name", "name2")
.verbose(true) .verbose(true)
.wError(true); .wError(true)
.wExtra(true);
var matches = List.of( var matches = List.of(
"-api-version", "11", "-api-version", "11",
"@" + localPath("file.txt"), "@" + localPath("file2.txt"),
"-classpath", localPath("path1", "path2"),
"-java-parameters", "-java-parameters",
"-jvm-target", "11", "-jvm-target", "11",
"-include-runtime", "-include-runtime",
@ -97,7 +95,8 @@ class CompileOptionsTest {
"-progressive", "-progressive",
"-script-templates", "name,name2", "-script-templates", "name,name2",
"-verbose", "-verbose",
"-Werror"); "-Werror",
"-Wextra");
var args = new ArrayList<List<String>>(); var args = new ArrayList<List<String>>();
args.add(options.args()); args.add(options.args());
@ -113,10 +112,9 @@ class CompileOptionsTest {
@Test @Test
void testArgsCollections() { void testArgsCollections() {
var advanceOptions = List.of("Xoption1", "Xoption2"); var advanceOptions = List.of("-Xoption1", "option=2");
var argFile = List.of(new File("arg1.txt"), new File("arg2.txt")); var argFile = List.of(new File("arg1.txt"), new File("arg2.txt"));
var classpath = List.of(new File("path1"), new File("path2")); var classpath = List.of(new File("path1"), new File("path2"));
var jvmOptions = List.of("option1", "option2");
var optIn = List.of("opt1", "opt2"); var optIn = List.of("opt1", "opt2");
var options = List.of("-foo", "-bar"); var options = List.of("-foo", "-bar");
var plugin = List.of("id:name:value", "id2:name2:value2"); var plugin = List.of("id:name:value", "id2:name2:value2");
@ -126,7 +124,6 @@ class CompileOptionsTest {
.advancedOptions(advanceOptions) .advancedOptions(advanceOptions)
.argFile(argFile) .argFile(argFile)
.classpath(classpath) .classpath(classpath)
.jvmOptions(jvmOptions)
.noStdLib(false) .noStdLib(false)
.optIn(optIn) .optIn(optIn)
.options(options) .options(options)
@ -144,8 +141,6 @@ class CompileOptionsTest {
.hasSize(argFile.size()).containsAll(argFile); .hasSize(argFile.size()).containsAll(argFile);
softly.assertThat(op.classpath()).as("classpath") softly.assertThat(op.classpath()).as("classpath")
.hasSize(classpath.size()).containsAll(classpath); .hasSize(classpath.size()).containsAll(classpath);
softly.assertThat(op.jvmOptions()).as("jvmOptions")
.hasSize(jvmOptions.size()).containsAll(jvmOptions);
softly.assertThat(op.optIn()).as("optIn") softly.assertThat(op.optIn()).as("optIn")
.hasSize(optIn.size()).containsAll(optIn); .hasSize(optIn.size()).containsAll(optIn);
softly.assertThat(op.options()).as("options") softly.assertThat(op.options()).as("options")
@ -165,7 +160,7 @@ class CompileOptionsTest {
"-foo", "-bar", "-foo", "-bar",
"-script-templates", "-script-templates",
"temp1,temp2", "temp1,temp2",
"-XXoption1", "-XXoption2", "-Xoption1", "-Xoption=2",
"-P", "plugin:id:name:value", "-P", "plugin:id:name:value",
"-P", "plugin:id2:name2:value2"); "-P", "plugin:id2:name2:value2");
@ -190,20 +185,27 @@ class CompileOptionsTest {
var bar = new File("bar.txt"); var bar = new File("bar.txt");
var options = new CompileOptions(); var options = new CompileOptions();
options = options.argFile(foo);
assertThat(options.argFile()).contains(foo);
options.argFile().clear();
assertThat(options.argFile()).isEmpty();
options.argFile(foo, bar); options.argFile(foo, bar);
assertThat(options.argFile()).contains(foo, bar); assertThat(options.argFile()).contains(foo, bar);
options.argFile().clear(); options.argFile().clear();
assertThat(options.argFile()).isEmpty();
options = options.argFile(foo.toPath(), bar.toPath()); options = options.argFile(foo.toPath(), bar.toPath());
assertThat(options.argFile()).contains(foo, bar); assertThat(options.argFile()).contains(foo, bar);
options.argFile().clear(); options.argFile().clear();
assertThat(options.argFile()).isEmpty();
options.argFile(foo.getAbsolutePath(), bar.getAbsolutePath()); options = options.argFile(foo.getAbsolutePath(), bar.getAbsolutePath());
assertThat(options.argFile()).contains(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath())); assertThat(options.argFile()).contains(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath()));
options.argFile().clear();
} }
@Test @Test
@EnabledOnOs(OS.LINUX)
void testCheckAllParams() throws IOException { void testCheckAllParams() throws IOException {
var args = Files.readAllLines(Paths.get("src", "test", "resources", "kotlinc-args.txt")); var args = Files.readAllLines(Paths.get("src", "test", "resources", "kotlinc-args.txt"));
@ -212,10 +214,7 @@ class CompileOptionsTest {
var params = new CompileOptions() var params = new CompileOptions()
.advancedOptions("Xoption") .advancedOptions("Xoption")
.apiVersion("11") .apiVersion("11")
.argFile("file")
.classpath("classpath")
.expression("expression") .expression("expression")
.jvmOptions("option")
.includeRuntime(true) .includeRuntime(true)
.javaParameters(true) .javaParameters(true)
.jdkHome("jdkhome") .jdkHome("jdkhome")
@ -234,7 +233,12 @@ class CompileOptionsTest {
.progressive(true) .progressive(true)
.scriptTemplates("template") .scriptTemplates("template")
.verbose(true) .verbose(true)
.wError(true); .wError(true)
.wExtra(true);
var skipArgs = List.of("-J", "-classpath", "@");
assertThat(args).as(skipArgs + " not found.").containsAll(skipArgs);
args.removeAll(skipArgs);
try (var softly = new AutoCloseableSoftAssertions()) { try (var softly = new AutoCloseableSoftAssertions()) {
for (var p : args) { for (var p : args) {
@ -256,31 +260,45 @@ class CompileOptionsTest {
var bar = new File("bar.txt"); var bar = new File("bar.txt");
var options = new CompileOptions(); var options = new CompileOptions();
options = options.classpath(foo);
assertThat(options.classpath()).as("File").containsExactly(foo);
options.classpath().clear();
assertThat(options.argFile()).isEmpty();
options.classpath(foo, bar); options.classpath(foo, bar);
assertThat(options.classpath()).as("File...").containsExactly(foo, bar); assertThat(options.classpath()).as("File...").containsExactly(foo, bar);
options.classpath().clear(); options.classpath().clear();
assertThat(options.argFile()).isEmpty();
options.classpath(List.of(foo, bar)); options.classpath(List.of(foo, bar));
assertThat(options.classpath()).as("List(File...)").containsExactly(foo, bar); assertThat(options.classpath()).as("List(File...)").containsExactly(foo, bar);
options.classpath().clear(); options.classpath().clear();
assertThat(options.argFile()).isEmpty();
options = options.classpath(foo.toPath(), bar.toPath()); options = options.classpath(foo.toPath(), bar.toPath());
assertThat(options.classpath()).as("Path...").containsExactly(foo, bar); assertThat(options.classpath()).as("Path...").containsExactly(foo, bar);
options.classpath().clear(); options.classpath().clear();
assertThat(options.argFile()).isEmpty();
options = options.classpathPaths(List.of(foo.toPath(), bar.toPath())); options = options.classpathPaths(List.of(foo.toPath(), bar.toPath()));
assertThat(options.classpath()).as("List(Path...)").containsExactly(foo, bar); assertThat(options.classpath()).as("List(Path...)").containsExactly(foo, bar);
options.classpath().clear(); options.classpath().clear();
assertThat(options.argFile()).isEmpty();
options.classpath(foo.getAbsolutePath(), bar.getAbsolutePath()); options.classpath(foo.getAbsolutePath(), bar.getAbsolutePath());
assertThat(options.classpath()).as("String...") assertThat(options.classpath()).as("String...")
.containsExactly(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath())); .containsExactly(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath()));
options.classpath().clear(); options.classpath().clear();
assertThat(options.argFile()).isEmpty();
options.classpathStrings(List.of(foo.getAbsolutePath(), bar.getAbsolutePath())); options.classpathStrings(List.of(foo.getAbsolutePath(), bar.getAbsolutePath()));
assertThat(options.classpath()).as("List(String...)") assertThat(options.classpath()).as("List(String...)")
.containsExactly(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath())); .containsExactly(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath()));
options.classpath().clear();
} }
@Test @Test
@ -340,7 +358,8 @@ class CompileOptionsTest {
.progressive(true) .progressive(true)
.scriptTemplates("name", "name2") .scriptTemplates("name", "name2")
.verbose(true) .verbose(true)
.wError(true); .wError(true)
.wExtra(true);
try (var softly = new AutoCloseableSoftAssertions()) { try (var softly = new AutoCloseableSoftAssertions()) {
softly.assertThat(options.advancedOptions()).containsExactly("xopt1", "xopt2"); softly.assertThat(options.advancedOptions()).containsExactly("xopt1", "xopt2");
@ -368,6 +387,7 @@ class CompileOptionsTest {
softly.assertThat(options.plugin()).containsExactly("id:name:value"); softly.assertThat(options.plugin()).containsExactly("id:name:value");
softly.assertThat(options.scriptTemplates()).containsExactly("name", "name2"); softly.assertThat(options.scriptTemplates()).containsExactly("name", "name2");
softly.assertThat(options.isWError()).isTrue(); softly.assertThat(options.isWError()).isTrue();
softly.assertThat(options.isWExtra()).isTrue();
} }
} }
} }

View file

@ -0,0 +1,78 @@
/*
* Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* 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 rife.bld.extension.kotlin;
import org.junit.jupiter.api.Test;
import rife.bld.extension.CompileKotlinOperation;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
class JvmOptionsTest {
@Test
void testop() {
var op = new CompileKotlinOperation().jvmOptions(new JvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED));
assertThat(op.jvmOptions()).as(JvmOptions.ALL_UNNAMED).containsExactly("--enable-native-access=ALL-UNNAMED");
op = new CompileKotlinOperation().jvmOptions(new JvmOptions().enableNativeAccess("m1", "m2"));
assertThat(op.jvmOptions()).as("m1,m2").containsExactly("--enable-native-access=m1,m2");
}
@Test
void testEnableNativeAccess() {
var options = new JvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED);
assertThat(options).as(JvmOptions.ALL_UNNAMED).containsExactly("--enable-native-access=ALL-UNNAMED");
options = new JvmOptions().enableNativeAccess("m1");
assertThat(options).as("m1").containsExactly("--enable-native-access=m1");
options = new JvmOptions().enableNativeAccess("m1", "m2");
assertThat(options).as("m1,m2").containsExactly("--enable-native-access=m1,m2");
}
@Test
void testIllegalNativeAccess() {
var options = new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.ALLOW);
assertThat(options).as("ALLOW").containsExactly("--illegal-native-access=allow");
options = new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.DENY);
assertThat(options).as("DENY").containsExactly("--illegal-native-access=deny");
options = new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.WARN);
assertThat(options).as("WARN").containsExactly("--illegal-native-access=warn");
}
@Test
void testJvmOptions() {
var op = new CompileKotlinOperation().jvmOptions("option1", "option2");
assertThat(op.jvmOptions()).as("option1,option2").containsExactly("option1", "option2");
op = new CompileKotlinOperation().jvmOptions(List.of("option1", "option2"));
assertThat(op.jvmOptions()).as("List.of(option1,option2)").containsExactly("option1", "option2");
op = op.jvmOptions(new JvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED));
assertThat(op.jvmOptions()).as("List.of(option1,option2,ALL_UNNAMED)")
.containsExactly("option1", "option2", "--enable-native-access=ALL-UNNAMED");
op = op.jvmOptions(new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.ALLOW));
assertThat(op.jvmOptions()).as("allow")
.containsExactly("option1", "option2", "--enable-native-access=ALL-UNNAMED",
"--illegal-native-access=allow");
}
}

View file

@ -0,0 +1,3 @@
-Xjdk-release=17 -no-reflect
-progressive

View file

@ -0,0 +1 @@
-include-runtime

View file

@ -22,4 +22,5 @@
-script-templates -script-templates
-verbose -verbose
-Werror -Werror
-Wextra
-X -X