CLI: fix non-XML rendering of argument parse error, simplify code

If the compiler is invoked through JPS, an instance of
XmlMessageRenderer is used and the output should be a valid XML.
Previously, we reported the argument parse error (and the note to try
"-help") before calling messageRenderer.renderPreamble, which resulted
in invalid XML. The same was happening for the usage printed on "-help".
Both of these problems are fixed

 #KT-14848 Fixed
This commit is contained in:
Alexander Udalov
2017-04-21 14:52:24 +03:00
parent a67382fdec
commit a802e7fb71
13 changed files with 135 additions and 53 deletions
@@ -42,21 +42,8 @@ abstract class CLITool<A : CommonToolArguments> {
): 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<A : CommonToolArguments> {
}
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<A : CommonToolArguments> {
// Used in kotlin-maven-plugin (KotlinCompileMojoBase)
protected abstract fun execImpl(messageCollector: MessageCollector, services: Services, arguments: A): ExitCode
private fun parseArguments(messageCollector: MessageCollector, args: Array<out String>): 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)
@@ -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 <A extends CommonToolArguments> void print(
@NotNull PrintStream target, @NotNull CLITool<A> compiler, @NotNull A arguments
) {
target.println("Usage: " + compiler.executableScriptFileName() + " <options> <source files>");
target.println("where " + (arguments.extraHelp ? "advanced" : "possible") + " options include:");
@NotNull
public static <A extends CommonToolArguments> String render(@NotNull CLITool<A> tool, @NotNull A arguments) {
StringBuilder sb = new StringBuilder();
appendln(sb, "Usage: " + tool.executableScriptFileName() + " <options> <source files>");
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);
}
}
@@ -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();
}
@@ -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 "";
@@ -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 "</MESSAGES>";