From 9fcc5cc3628a448f092da3454e3fdca0d03a0f50 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 21 Mar 2025 13:22:16 -0700 Subject: [PATCH 1/2] Add test for fromProject() using the examples project --- .idea/runConfigurations/Run Tests.xml | 9 --------- .../rife/bld/extension/CompileKotlinOperationTest.java | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 .idea/runConfigurations/Run Tests.xml diff --git a/.idea/runConfigurations/Run Tests.xml b/.idea/runConfigurations/Run Tests.xml deleted file mode 100644 index 057a90e..0000000 --- a/.idea/runConfigurations/Run Tests.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java b/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java index 2c9032d..337b3a7 100644 --- a/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java +++ b/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java @@ -209,6 +209,15 @@ class CompileKotlinOperationTest { } } + @Test + void testFromProject() { + var examples = new File("examples"); + var op = new CompileKotlinOperation().fromProject( + new BaseProjectBlueprint(examples, "com.example", "examples", "examples")); + assertThat(op.mainSourceDirectories()).contains(new File(examples, "src/main/kotlin")); + assertThat(op.testSourceDirectories()).contains(new File(examples, "src/test/kotlin")); + } + @Test void testFromProjectNoKotlin() { var op = new CompileKotlinOperation().fromProject( From a57ae52a1c6b696304e3985ceb9f3c6a0e41cf07 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 21 Mar 2025 21:08:13 -0700 Subject: [PATCH 2/2] Add method to locate the Kotlin compiler in common locations --- README.md | 8 + .../bld/extension/CompileKotlinOperation.java | 185 +++++++++++++++--- .../extension/CompileKotlinOperationTest.java | 21 ++ .../extension/kotlin/CompileOptionsTest.java | 1 - 4 files changed, 189 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index d0d0ff9..06ce2cb 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,14 @@ for all available configuration options. Please make sure the Kotlin compiler is [installed](https://kotlinlang.org/docs/command-line.html#install-the-compiler). +The plugin will look in common locations such as: +- `KOTLIN_HOME` +- `PATH` +- SDKMAN! +- Homebrew +- JetBrains Toolbox (IntelliJ IDEA, Android Studio) +- etc. + You can also manually configure the Kotlin home location as follows: ```java diff --git a/src/main/java/rife/bld/extension/CompileKotlinOperation.java b/src/main/java/rife/bld/extension/CompileKotlinOperation.java index 570ff14..f1c912b 100644 --- a/src/main/java/rife/bld/extension/CompileKotlinOperation.java +++ b/src/main/java/rife/bld/extension/CompileKotlinOperation.java @@ -26,9 +26,7 @@ import rife.tools.FileUtils; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -40,6 +38,9 @@ import java.util.logging.Logger; */ public class CompileKotlinOperation extends AbstractOperation { 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 compileMainClasspath_ = new ArrayList<>(); private final Collection compileTestClasspath_ = new ArrayList<>(); private final Collection mainSourceDirectories_ = new ArrayList<>(); @@ -55,6 +56,145 @@ public class CompileKotlinOperation extends AbstractOperation commonPaths = new ArrayList<>(); + + if (isLinux()) { + commonPaths.add("/usr/bin"); + commonPaths.add("/usr/local/bin"); + commonPaths.add("/usr/local/kotlin/bin"); + commonPaths.add("/opt/kotlin/bin"); + var userHome = System.getProperty("user.home"); + if (userHome != null) { + commonPaths.add(userHome + "/.sdkman/candidates/kotlin/current/bin"); // SDKMAN! + commonPaths.add(userHome + "/.local/share/JetBrains/Toolbox/apps/intellij-idea-ultimate/plugins/Kotlin/bin"); // Toolbox IDEA Ultimate + commonPaths.add(userHome + "/.local/share/JetBrains/Toolbox/apps/intellij-idea-community-edition/plugins/Kotlin/bin"); // Toolbox IDEA CE + commonPaths.add(userHome + "/.local/share/JetBrains/Toolbox/apps/android-studio/plugins/Kotlin/bin"); // Toolbox Android Studio + } + } else if (isWindows()) { + var localAppData = System.getenv("LOCALAPPDATA"); + if (localAppData != null) { + commonPaths.add(localAppData + "\\Programs\\IntelliJ IDEA Ultimate\\plugins\\Kotlin\\kotlinc\\bin"); // Toolbox IDEA Ultimate + commonPaths.add(localAppData + "\\Programs\\IntelliJ IDEA Community Edition\\plugins\\Kotlin\\kotlinc\\bin"); // Toolbox IDEA CE + commonPaths.add(localAppData + "\\Programs\\Android Studio\\plugins\\Kotlin\\kotlinc\\bin"); // Toolbox Android Studio + } + var programFiles = System.getenv("ProgramFiles"); + if (programFiles != null) { + commonPaths.add(programFiles + File.separator + "Kotlin"); + } + } else if (isMacOS()) { + commonPaths.add("/usr/local/bin"); // Homebrew + commonPaths.add("/opt/homebrew/bin"); // Homebrew + var userHome = System.getProperty("user.home"); + if (userHome != null) { + commonPaths.add(userHome + "/.sdkman/candidates/kotlin/current/bin"); // SDKMAN! + } + commonPaths.add("/Applications/IntelliJ IDEA Ultimate.app/Contents/plugins/Kotlin/bin"); //IntelliJ IDEA Ultimate + commonPaths.add("/Applications/IntelliJ IDEA.app/Contents/plugins/Kotlin/bin"); //IntelliJ IDEA + commonPaths.add("/Applications/Android Studio.app/Contents/plugins/Kotlin/bin"); //Android Studio + } + + for (var location : commonPaths) { + kotlincPath = findKotlincInDir(location); + if (kotlincPath != null) { + 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))) { + 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. + */ + 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. + */ + public static boolean isMacOS() { + return OS_NAME != null && (OS_NAME.contains("mac") || OS_NAME.contains("darwin")); + } + /** * Determines if the given string is not blank. * @@ -65,6 +205,15 @@ public class CompileKotlinOperation extends AbstractOperation(); // kotlinc - args.add(kotlinCompiler()); + if (kotlinc_ != null) { + args.add(kotlinc_.getAbsolutePath()); + } else if (kotlinHome_ != null) { + args.add(Objects.requireNonNullElseGet(findKotlincInDir(kotlinHome_.getAbsolutePath()), + CompileKotlinOperation::findKotlincPath)); + } else { + args.add(findKotlincPath()); + } // classpath if (classpath != null && !classpath.isEmpty()) { @@ -386,7 +542,6 @@ public class CompileKotlinOperation extends AbstractOperation * Sets the following from the project: *
    - *
  • {@link #kotlinHome() kotlinHome} to the {@code KOTLIN_HOME} environment variable, if set.
  • *
  • {@link #workDir() workDir} to the project's directory.
  • *
  • {@link #buildMainDirectory() buildMainDirectory}
  • *
  • {@link #buildTestDirectory() buildTestDirectory}
  • @@ -405,14 +560,6 @@ public class CompileKotlinOperation extends AbstractOperation