From d5e4775bcd027dd35f8e3e7bd808b7889e1c9776 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 26 Feb 2015 19:37:47 +0300 Subject: [PATCH] Show plugin usage on invalid arguments --- .../kotlin/cli/jvm/K2JVMCompiler.java | 7 ++++- .../kotlin/cli/jvm/PluginCliParser.kt | 17 ++++++------ .../kotlin/compiler/plugin/CliOptions.kt | 27 ++++++++++++++++++- .../testData/cli/jvm/pluginSimpleUsage.args | 10 +++++++ .../testData/cli/jvm/pluginSimpleUsage.kt | 8 ++++++ .../testData/cli/jvm/pluginSimpleUsage.out | 7 +++++ .../jetbrains/kotlin/cli/CliCommonTest.java | 5 ++++ 7 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/cli/jvm/pluginSimpleUsage.args create mode 100644 compiler/testData/cli/jvm/pluginSimpleUsage.kt create mode 100644 compiler/testData/cli/jvm/pluginSimpleUsage.out diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java index 1db5f2d0090..cee07bdbfb4 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.cli.common.modules.ModuleScriptData; import org.jetbrains.kotlin.cli.jvm.compiler.*; import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal; import org.jetbrains.kotlin.codegen.CompilationException; -import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException; +import org.jetbrains.kotlin.compiler.plugin.*; import org.jetbrains.kotlin.config.CommonConfigurationKeys; import org.jetbrains.kotlin.config.CompilerConfiguration; import org.jetbrains.kotlin.config.Services; @@ -94,6 +94,11 @@ public class K2JVMCompiler extends CLICompiler { try { PluginCliParser.loadPlugins(arguments, configuration); } + catch (PluginCliOptionProcessingException e) { + String message = e.getMessage() + "\n\n" + PluginPackage.cliPluginUsageString(e.getPluginId(), e.getOptions()); + messageCollector.report(CompilerMessageSeverity.ERROR, message, CompilerMessageLocation.NO_LOCATION); + return INTERNAL_ERROR; + } catch (CliOptionProcessingException e) { messageCollector.report(CompilerMessageSeverity.ERROR, e.getMessage(), CompilerMessageLocation.NO_LOCATION); return INTERNAL_ERROR; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/PluginCliParser.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/PluginCliParser.kt index d4938894cf1..e0cd7aa7c55 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/PluginCliParser.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/PluginCliParser.kt @@ -16,26 +16,21 @@ package org.jetbrains.kotlin.cli.jvm -import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor import kotlin.platform.* import java.util.jar.JarFile import java.util.jar.Attributes -import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException import java.util.regex.Pattern import com.intellij.util.containers.MultiMap -import org.jetbrains.kotlin.compiler.plugin.CliOption import java.net.URLClassLoader import java.net.URL import java.io.File -import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import java.util.ServiceLoader import java.io.IOException import java.util.Enumeration -import org.jetbrains.kotlin.compiler.plugin.parsePluginOption -import org.jetbrains.kotlin.compiler.plugin.CliOptionValue import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.utils.valuesToMap import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.compiler.plugin.* public object PluginCliParser { @@ -85,10 +80,16 @@ public object PluginCliParser { for (option in processor.pluginOptions) { val values = optionsToValues[option] if (option.required && values.isEmpty()) { - throw CliOptionProcessingException("Required plugin option not present: ${processor.pluginId}:${option.name}") + throw PluginCliOptionProcessingException( + processor.pluginId, + processor.pluginOptions, + "Required plugin option not present: ${processor.pluginId}:${option.name}") } if (!option.allowMultipleOccurrences && values.size() > 1) { - throw CliOptionProcessingException("Multiple values not allowed for plugin option ${processor.pluginId}:${option.name}") + throw PluginCliOptionProcessingException( + processor.pluginId, + processor.pluginOptions, + "Multiple values are not allowed for plugin option ${processor.pluginId}:${option.name}") } for (value in values) { diff --git a/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CliOptions.kt b/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CliOptions.kt index 441ca2b746f..ad2f64294cf 100644 --- a/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CliOptions.kt +++ b/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CliOptions.kt @@ -26,7 +26,32 @@ public class CliOption( public val allowMultipleOccurrences: Boolean = false ) -public class CliOptionProcessingException(message: String, cause: Throwable? = null): RuntimeException(message, cause) +public open class CliOptionProcessingException(message: String, cause: Throwable? = null): RuntimeException(message, cause) + +public class PluginCliOptionProcessingException( + val pluginId: String, + val options: Collection, + message: String, + cause: Throwable? = null +): CliOptionProcessingException(message, cause) + +public fun cliPluginUsageString(pluginId: String, options: Collection): String { + val LEFT_INDENT = 2 + val MAX_OPTION_WIDTH = 26 + + val renderedOptions = options.map { + val name = "${it.name} ${it.valueDescription}" + val margin = if (name.length() > MAX_OPTION_WIDTH) { + "\n" + " ".repeat(MAX_OPTION_WIDTH + LEFT_INDENT + 1) + } else " ".repeat(1 + MAX_OPTION_WIDTH - name.length()) + + val modifiers = (if (it.required) "required" else "") + (if (it.allowMultipleOccurrences) "multiple" else "") + val modifiersEnclosed = if (modifiers.isNotEmpty()) " ($modifiers)" else "" + + " ".repeat(LEFT_INDENT) + name + margin + it.description + modifiersEnclosed + } + return "Plugin \"$pluginId\" usage:\n" + renderedOptions.joinToString("\n", postfix = "\n") +} public data class CliOptionValue( val pluginId: String, diff --git a/compiler/testData/cli/jvm/pluginSimpleUsage.args b/compiler/testData/cli/jvm/pluginSimpleUsage.args new file mode 100644 index 00000000000..0685954258a --- /dev/null +++ b/compiler/testData/cli/jvm/pluginSimpleUsage.args @@ -0,0 +1,10 @@ +-d +$TEMP_DIR$ +-Xplugin +dist/kotlinc/lib/android-compiler-plugin.jar +-P +plugin:org.jetbrains.kotlin.android:androidManifest=$TESTDATA_DIR$/androidPlugin/AndroidManifest.xml +$TESTDATA_DIR$/pluginSimple.kt +$TESTDATA_DIR$/androidPlugin/androidApp.kt +$TESTDATA_DIR$/androidPlugin/androidView.kt +$TESTDATA_DIR$/androidPlugin/androidWidget.kt \ No newline at end of file diff --git a/compiler/testData/cli/jvm/pluginSimpleUsage.kt b/compiler/testData/cli/jvm/pluginSimpleUsage.kt new file mode 100644 index 00000000000..ca0ce75a79a --- /dev/null +++ b/compiler/testData/cli/jvm/pluginSimpleUsage.kt @@ -0,0 +1,8 @@ +import android.view.* +import android.app.* +import android.widget.* +import kotlinx.android.synthetic.layout.* + +class MyActivity : Activity() { + { textView.setText("Some text") } +} \ No newline at end of file diff --git a/compiler/testData/cli/jvm/pluginSimpleUsage.out b/compiler/testData/cli/jvm/pluginSimpleUsage.out new file mode 100644 index 00000000000..87abb501352 --- /dev/null +++ b/compiler/testData/cli/jvm/pluginSimpleUsage.out @@ -0,0 +1,7 @@ +ERROR: Required plugin option not present: org.jetbrains.kotlin.android:androidRes + +Plugin "org.jetbrains.kotlin.android" usage: + androidRes Android resources path (required) + androidManifest Android manifest file (required) + +COMPILATION_ERROR \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliCommonTest.java b/compiler/tests/org/jetbrains/kotlin/cli/CliCommonTest.java index bd3d407c33b..f9631cf9902 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliCommonTest.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliCommonTest.java @@ -77,4 +77,9 @@ public class CliCommonTest extends CliBaseTest { public void pluginSimple() throws Exception { executeCompilerCompareOutputJVM(); } + + @Test + public void pluginSimpleUsage() throws Exception { + executeCompilerCompareOutputJVM(); + } }