diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt
index ceda801e555..394fdfce355 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt
@@ -42,21 +42,8 @@ abstract class CLITool {
): ExitCode {
K2JVMCompiler.resetInitStartTime()
- val parseArgumentsCollector = PrintingMessageCollector(errStream, messageRenderer, false)
- val arguments = try {
- parseArguments(parseArgumentsCollector, args) ?: return ExitCode.INTERNAL_ERROR
- }
- catch (e: IllegalArgumentException) {
- parseArgumentsCollector.report(CompilerMessageSeverity.ERROR, e.message!!, null)
- parseArgumentsCollector.report(CompilerMessageSeverity.INFO, "Use -help for more information", null)
- return ExitCode.COMPILATION_ERROR
- }
-
- if (arguments.help || arguments.extraHelp) {
- Usage.print(errStream, this, arguments)
- return ExitCode.OK
- }
-
+ val arguments = createArguments()
+ parseCommandLineArguments(args, arguments)
val collector = PrintingMessageCollector(errStream, messageRenderer, arguments.verbose)
try {
@@ -65,6 +52,19 @@ abstract class CLITool {
}
errStream.print(messageRenderer.renderPreamble())
+
+ val errorMessage = validateArguments(arguments.errors)
+ if (errorMessage != null) {
+ collector.report(CompilerMessageSeverity.ERROR, errorMessage, null)
+ collector.report(CompilerMessageSeverity.INFO, "Use -help for more information", null)
+ return ExitCode.COMPILATION_ERROR
+ }
+
+ if (arguments.help || arguments.extraHelp) {
+ errStream.print(messageRenderer.renderUsage(Usage.render(this, arguments)))
+ return ExitCode.OK
+ }
+
return exec(collector, services, arguments)
}
finally {
@@ -93,19 +93,6 @@ abstract class CLITool {
// Used in kotlin-maven-plugin (KotlinCompileMojoBase)
protected abstract fun execImpl(messageCollector: MessageCollector, services: Services, arguments: A): ExitCode
- private fun parseArguments(messageCollector: MessageCollector, args: Array): A? {
- return try {
- createArguments().also { parseArguments(args, it) }
- }
- catch (e: IllegalArgumentException) {
- throw e
- }
- catch (t: Throwable) {
- messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(t), null)
- null
- }
- }
-
abstract fun createArguments(): A
// Used in kotlin-maven-plugin (KotlinCompileMojoBase) and in kotlin-gradle-plugin (KotlinJvmOptionsImpl, KotlinJsOptionsImpl)
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java
index d217174075c..6a901736721 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java
@@ -18,46 +18,43 @@ package org.jetbrains.kotlin.cli.common;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cli.common.arguments.Argument;
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments;
import org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt;
-import java.io.PrintStream;
import java.lang.reflect.Field;
-class Usage {
+public class Usage {
// The magic number 29 corresponds to the similar padding width in javac and scalac command line compilers
private static final int OPTION_NAME_PADDING_WIDTH = 29;
- public static void print(
- @NotNull PrintStream target, @NotNull CLITool compiler, @NotNull A arguments
- ) {
- target.println("Usage: " + compiler.executableScriptFileName() + " ");
- target.println("where " + (arguments.extraHelp ? "advanced" : "possible") + " options include:");
+ @NotNull
+ public static String render(@NotNull CLITool tool, @NotNull A arguments) {
+ StringBuilder sb = new StringBuilder();
+ appendln(sb, "Usage: " + tool.executableScriptFileName() + " ");
+ appendln(sb, "where " + (arguments.extraHelp ? "advanced" : "possible") + " options include:");
for (Class> clazz = arguments.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
for (Field field : clazz.getDeclaredFields()) {
- String usage = fieldUsage(field, arguments.extraHelp);
- if (usage != null) {
- target.println(usage);
- }
+ fieldUsage(sb, field, arguments.extraHelp);
}
}
if (arguments.extraHelp) {
- target.println();
- target.println("Advanced options are non-standard and may be changed or removed without any notice.");
+ appendln(sb, "");
+ appendln(sb, "Advanced options are non-standard and may be changed or removed without any notice.");
}
+
+ return sb.toString();
}
- @Nullable
- private static String fieldUsage(@NotNull Field field, boolean extraHelp) {
+ private static void fieldUsage(@NotNull StringBuilder sb, @NotNull Field field, boolean extraHelp) {
Argument argument = field.getAnnotation(Argument.class);
- if (argument == null) return null;
+ if (argument == null) return;
- if (extraHelp != ParseCommandLineArgumentsKt.isAdvanced(argument)) return null;
+ if (extraHelp != ParseCommandLineArgumentsKt.isAdvanced(argument)) return;
- StringBuilder sb = new StringBuilder(" ");
+ int startLength = sb.length();
+ sb.append(" ");
sb.append(argument.value());
if (!argument.shortName().isEmpty()) {
@@ -71,17 +68,21 @@ class Usage {
sb.append(argument.valueDescription());
}
- int width = OPTION_NAME_PADDING_WIDTH - 1;
- if (sb.length() >= width + 5) { // Break the line if it's too long
+ int margin = startLength + OPTION_NAME_PADDING_WIDTH - 1;
+ if (sb.length() >= margin + 5) { // Break the line if it's too long
sb.append("\n");
- width += sb.length();
+ margin += sb.length() - startLength;
}
- while (sb.length() < width) {
+ while (sb.length() < margin) {
sb.append(" ");
}
sb.append(" ");
- sb.append(argument.description().replace("\n", "\n" + StringsKt.repeat(" ", OPTION_NAME_PADDING_WIDTH)));
- return sb.toString();
+ appendln(sb, argument.description().replace("\n", "\n" + StringsKt.repeat(" ", OPTION_NAME_PADDING_WIDTH)));
+ }
+
+ private static void appendln(@NotNull StringBuilder sb, @NotNull String string) {
+ sb.append(string);
+ StringsKt.appendln(sb);
}
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java
index 4f00ba3e920..d10664f8f6b 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java
@@ -56,5 +56,7 @@ public interface MessageRenderer {
String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @Nullable CompilerMessageLocation location);
+ String renderUsage(@NotNull String usage);
+
String renderConclusion();
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java
index 9103f664c2d..03edd893fd1 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java
@@ -157,6 +157,11 @@ public abstract class PlainTextMessageRenderer implements MessageRenderer {
@Nullable
protected abstract String getPath(@NotNull CompilerMessageLocation location);
+ @Override
+ public String renderUsage(@NotNull String usage) {
+ return usage;
+ }
+
@Override
public String renderConclusion() {
return "";
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java
index fb8d07944c1..b5702fce182 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java
@@ -48,6 +48,11 @@ public class XmlMessageRenderer implements MessageRenderer {
return StringUtil.escapeXml(str);
}
+ @Override
+ public String renderUsage(@NotNull String usage) {
+ return render(CompilerMessageSeverity.STRONG_WARNING, usage, null);
+ }
+
@Override
public String renderConclusion() {
return "";
diff --git a/jps-plugin/jps-tests/jps-tests.iml b/jps-plugin/jps-tests/jps-tests.iml
index 1772d1a64c3..4cec7e15e41 100644
--- a/jps-plugin/jps-tests/jps-tests.iml
+++ b/jps-plugin/jps-tests/jps-tests.iml
@@ -19,5 +19,6 @@
+
\ No newline at end of file
diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt
index 944ed4380cd..d8f87476e2e 100644
--- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt
+++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt
@@ -51,6 +51,9 @@ import org.jetbrains.jps.model.java.JpsJavaSdkType
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.util.JpsPathUtil
+import org.jetbrains.kotlin.cli.common.Usage
+import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
+import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.config.KotlinCompilerVersion.TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY
@@ -787,6 +790,26 @@ class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
)
}
+ fun testHelp() {
+ initProject()
+
+ val result = buildAllModules()
+ result.assertSuccessful()
+ val warning = result.getMessages(BuildMessage.Kind.WARNING).single()
+
+ Assert.assertEquals(Usage.render(K2JVMCompiler(), K2JVMCompilerArguments()), warning.messageText)
+ }
+
+ fun testWrongArgument() {
+ initProject()
+
+ val result = buildAllModules()
+ result.assertFailed()
+ val errors = result.getMessages(BuildMessage.Kind.ERROR).joinToString("\n\n") { it.messageText }
+
+ Assert.assertEquals("Invalid argument: -abcdefghij-invalid-argument", errors)
+ }
+
fun testCodeInKotlinPackage() {
initProject(JVM_MOCK_RUNTIME)
diff --git a/jps-plugin/testData/general/Help/kotlinProject.iml b/jps-plugin/testData/general/Help/kotlinProject.iml
new file mode 100644
index 00000000000..a0cbe548242
--- /dev/null
+++ b/jps-plugin/testData/general/Help/kotlinProject.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps-plugin/testData/general/Help/kotlinProject.ipr b/jps-plugin/testData/general/Help/kotlinProject.ipr
new file mode 100644
index 00000000000..102bdf0ea20
--- /dev/null
+++ b/jps-plugin/testData/general/Help/kotlinProject.ipr
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jps-plugin/testData/general/Help/src/test.kt b/jps-plugin/testData/general/Help/src/test.kt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jps-plugin/testData/general/WrongArgument/kotlinProject.iml b/jps-plugin/testData/general/WrongArgument/kotlinProject.iml
new file mode 100644
index 00000000000..a0cbe548242
--- /dev/null
+++ b/jps-plugin/testData/general/WrongArgument/kotlinProject.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps-plugin/testData/general/WrongArgument/kotlinProject.ipr b/jps-plugin/testData/general/WrongArgument/kotlinProject.ipr
new file mode 100644
index 00000000000..a9c7f866ea1
--- /dev/null
+++ b/jps-plugin/testData/general/WrongArgument/kotlinProject.ipr
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jps-plugin/testData/general/WrongArgument/src/test.kt b/jps-plugin/testData/general/WrongArgument/src/test.kt
new file mode 100644
index 00000000000..e69de29bb2d