From b0d6a3ac3b63c769c4bd9be1036302056306ccaf Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 23 Mar 2025 02:30:17 -0700 Subject: [PATCH] Pass arguments to kotlinc via @argfile --- .../bld/extension/CompileKotlinOperation.java | 73 ++++++++++++++----- .../bld/extension/kotlin/CompileOptions.java | 8 -- .../extension/CompileKotlinOperationTest.java | 4 +- .../extension/kotlin/CompileOptionsTest.java | 7 +- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/main/java/rife/bld/extension/CompileKotlinOperation.java b/src/main/java/rife/bld/extension/CompileKotlinOperation.java index c093bdd..8f7372e 100644 --- a/src/main/java/rife/bld/extension/CompileKotlinOperation.java +++ b/src/main/java/rife/bld/extension/CompileKotlinOperation.java @@ -26,6 +26,7 @@ import rife.tools.FileUtils; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.logging.Level; @@ -319,6 +320,17 @@ public class CompileKotlinOperation extends AbstractOperation classpath, Collection sources, File destination, File friendPaths) throws ExitStatusException { + + var cp = new ArrayList(); + if (classpath != null && !classpath.isEmpty()) { + cp.addAll(classpath); + } + if (sources.isEmpty()) { if (!silent() && LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning("Nothing to compile."); @@ -470,60 +488,75 @@ public class CompileKotlinOperation extends AbstractOperation(); var args = new ArrayList(); // kotlinc if (kotlinc_ != null) { - args.add(kotlinc_.getAbsolutePath()); + command.add(kotlinc_.getAbsolutePath()); } else if (kotlinHome_ != null) { - args.add(Objects.requireNonNullElseGet(findKotlincInDir(kotlinHome_.getAbsolutePath()), + command.add(Objects.requireNonNullElseGet(findKotlincInDir(kotlinHome_.getAbsolutePath()), CompileKotlinOperation::findKotlincPath)); } else { - args.add(findKotlincPath(silent())); + command.add(findKotlincPath(silent())); } + // JVM options if (!jvmOptions_.isEmpty()) { jvmOptions_.forEach(s -> command.add("-J" + s)); } + // compiler options + if (compileOptions_ != null) { + args.addAll(compileOptions_.args()); + cp.addAll(compileOptions_.classpath().stream().map(this::cleanPath).toList()); + } + // classpath - if (classpath != null && !classpath.isEmpty()) { + if (!cp.isEmpty()) { args.add("-cp"); - args.add(FileUtils.joinPaths(classpath.stream().toList())); + args.add('"' + FileUtils.joinPaths(cp.stream().map(this::cleanPath).toList()) + '"'); } // destination args.add("-d"); - args.add(destination.getAbsolutePath()); + args.add('"' + cleanPath(destination) + '"'); // friend-path if (friendPaths != null && friendPaths.exists()) { - args.add("-Xfriend-paths=" + friendPaths.getAbsolutePath()); - } - - // options - if (compileOptions_ != null) { - args.addAll(compileOptions_.args()); + args.add("-Xfriend-paths=\"" + cleanPath(friendPaths) + '"'); } // plugins if (!plugins_.isEmpty()) { - plugins_.forEach(p -> args.add("-Xplugin=" + p)); + plugins_.forEach(p -> args.add("-Xplugin=\"" + cleanPath(p) + '"')); } // 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()) { - LOGGER.fine(String.join(" ", args)); + LOGGER.fine(String.join(" ", command) + " " + argsLine); } - var pb = new ProcessBuilder(); - pb.inheritIO(); - pb.command(args); - pb.directory(workDir_); - 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(); proc.waitFor(); ExitStatusException.throwOnFailure(proc.exitValue()); diff --git a/src/main/java/rife/bld/extension/kotlin/CompileOptions.java b/src/main/java/rife/bld/extension/kotlin/CompileOptions.java index 6c9382c..3e0e8bf 100644 --- a/src/main/java/rife/bld/extension/kotlin/CompileOptions.java +++ b/src/main/java/rife/bld/extension/kotlin/CompileOptions.java @@ -23,7 +23,6 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import static rife.bld.extension.CompileKotlinOperation.isNotBlank; @@ -111,7 +110,6 @@ public class CompileOptions { return this; } - /** * Allow using declarations only from the specified version of Kotlin bundled libraries. * @@ -253,12 +251,6 @@ public class CompileOptions { argFile_.forEach(f -> args.add("@" + f.getAbsolutePath())); } - // classpath - if (!classpath_.isEmpty()) { - args.add("-classpath"); - args.add(classpath_.stream().map(File::getAbsolutePath).collect(Collectors.joining(File.pathSeparator))); - } - // expression if (isNotBlank(expression_)) { args.add("-expression"); diff --git a/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java b/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java index e077341..fc8aab2 100644 --- a/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java +++ b/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java @@ -224,8 +224,8 @@ class CompileKotlinOperationTest { 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")); + assertThat(op.mainSourceDirectories()).containsExactly(new File(examples, "src/main/kotlin")); + assertThat(op.testSourceDirectories()).containsExactly(new File(examples, "src/test/kotlin")); } @Test diff --git a/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java b/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java index eaf2f44..02f9a59 100644 --- a/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java +++ b/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java @@ -51,7 +51,6 @@ class CompileOptionsTest { var options = new CompileOptions() .apiVersion("11") .argFile(new File("file.txt"), new File("file2.txt")) - .classpath(new File("path1"), new File("path2")) .javaParameters(true) .jvmTarget("11") .includeRuntime(true) @@ -76,7 +75,6 @@ class CompileOptionsTest { var matches = List.of( "-api-version", "11", "@" + localPath("file.txt"), "@" + localPath("file2.txt"), - "-classpath", localPath("path1", "path2"), "-java-parameters", "-jvm-target", "11", "-include-runtime", @@ -210,7 +208,6 @@ class CompileOptionsTest { .advancedOptions("Xoption") .apiVersion("11") .argFile("file") - .classpath("classpath") .expression("expression") .includeRuntime(true) .javaParameters(true) @@ -233,6 +230,10 @@ class CompileOptionsTest { .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()) { for (var p : args) { var found = false;