CommandLineProcessor infrastructure added
This commit is contained in:
committed by
Yan Zhulanow
parent
565ce5a781
commit
d961e2f5b4
+10
@@ -23,6 +23,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class CommonCompilerArguments {
|
||||
public static final String PLUGIN_OPTION_FORMAT = "<pluginId>:<optionName>=<value>";
|
||||
|
||||
@Argument(value = "nowarn", description = "Generate no warnings")
|
||||
public boolean suppressWarnings;
|
||||
|
||||
@@ -41,6 +43,14 @@ public abstract class CommonCompilerArguments {
|
||||
@Argument(value = "Xno-inline", description = "Disable method inlining")
|
||||
public boolean noInline;
|
||||
|
||||
@Argument(value = "Xplugin", description = "Load a plugin from the given classpath")
|
||||
@ValueDescription("<path>")
|
||||
public String[] pluginClasspaths;
|
||||
|
||||
@Argument(value = "P", description = "Pass an option to a plugin")
|
||||
@ValueDescription(PLUGIN_OPTION_FORMAT)
|
||||
public String[] pluginOptions;
|
||||
|
||||
public List<String> freeArgs = new SmartList<String>();
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.cli.jvm
|
||||
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.jet.cli.common.arguments.CommonCompilerArguments
|
||||
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 org.jetbrains.jet.utils.valuesToMap
|
||||
import org.jetbrains.jet.config.CompilerConfiguration
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||
|
||||
public object PluginCliParser {
|
||||
|
||||
public val PLUGIN_ARGUMENT_PREFIX: String = "plugin:"
|
||||
|
||||
private fun getCommandLineProcessors(arguments: CommonCompilerArguments): Collection<CommandLineProcessor> {
|
||||
return arguments.pluginClasspaths!!.map {
|
||||
loadCommandLineProcessor(JarFile(it).getManifest()?.getAttributes("org.jetbrains.kotlin.compiler.plugin"))
|
||||
}.filterNotNull()
|
||||
}
|
||||
|
||||
private fun loadCommandLineProcessor(attributes: Attributes?): CommandLineProcessor? {
|
||||
if (attributes == null) return null
|
||||
|
||||
val processorClassName = attributes.getValue("CommandLineProcessor")
|
||||
if (processorClassName == null) return null
|
||||
|
||||
try {
|
||||
val processorClass = Class.forName(processorClassName)
|
||||
return processorClass.newInstance() as CommandLineProcessor
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
throw CliOptionProcessingException("Loading plugin component failed: $processorClassName", e)
|
||||
}
|
||||
}
|
||||
|
||||
[platformStatic]
|
||||
fun processPluginOptions(arguments: CommonCompilerArguments, configuration: CompilerConfiguration) {
|
||||
val optionValuesByPlugin = arguments.pluginOptions!!.map { parsePluginOption(it) }.groupBy {
|
||||
if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}")
|
||||
it.optionName
|
||||
}
|
||||
|
||||
val processors = getCommandLineProcessors(arguments)
|
||||
for (processor in processors) {
|
||||
val declaredOptions = processor.pluginOptions.valuesToMap { it.name }
|
||||
val optionsToValues = MultiMap<CliOption, PluginOptionValue>()
|
||||
|
||||
for (optionValue in optionValuesByPlugin[processor.pluginId].orEmpty()) {
|
||||
val option = declaredOptions[optionValue!!.optionName]
|
||||
if (option == null) {
|
||||
throw CliOptionProcessingException("Unsupported plugin option: $optionValue")
|
||||
}
|
||||
optionsToValues.putValue(option, optionValue)
|
||||
}
|
||||
|
||||
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}")
|
||||
}
|
||||
if (!option.allowMultipleOccurrences && values.size() > 1) {
|
||||
throw CliOptionProcessingException("Multiple values not allowed for plugin option ${processor.pluginId}:${option.name}")
|
||||
}
|
||||
|
||||
for (value in values) {
|
||||
processor.processOption(option, value.value, configuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PluginOptionValue(
|
||||
val pluginId: String,
|
||||
val optionName: String,
|
||||
val value: String
|
||||
) {
|
||||
override fun toString() = "$pluginId:$optionName=$value"
|
||||
}
|
||||
|
||||
private fun parsePluginOption(argumentValue: String): PluginOptionValue? {
|
||||
val pattern = Pattern.compile("""^([^:]*):([^=]*)=(.*)$""")
|
||||
val matcher = pattern.matcher(argumentValue)
|
||||
if (matcher.matches()) {
|
||||
return PluginOptionValue(matcher.group(1)!!, matcher.group(2)!!, matcher.group(3)!!)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.cli.jvm.PluginCliParser;
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode;
|
||||
@@ -29,6 +30,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.config.CommonConfigurationKeys;
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
||||
import org.jetbrains.kotlin.config.Services;
|
||||
@@ -90,12 +92,13 @@ public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
return INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (arguments.androidRes != null) {
|
||||
configuration.put(JVMConfigurationKeys.ANDROID_RES_PATH, arguments.androidRes);
|
||||
try {
|
||||
PluginCliParser.processPluginOptions(arguments, configuration);
|
||||
}
|
||||
|
||||
if (arguments.androidManifest != null) {
|
||||
configuration.put(JVMConfigurationKeys.ANDROID_MANIFEST, arguments.androidManifest);
|
||||
catch (CliOptionProcessingException e) {
|
||||
// TODO Print usage?
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, e.getMessage(), CompilerMessageLocation.NO_LOCATION);
|
||||
return INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (arguments.script) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="intellij-core" level="project" />
|
||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.compiler.plugin
|
||||
|
||||
import org.jetbrains.jet.config.CompilerConfiguration
|
||||
|
||||
public class CliOption(
|
||||
public val name: String,
|
||||
public val valueDescription: String,
|
||||
public val description: String,
|
||||
public val required: Boolean = true,
|
||||
public val allowMultipleOccurrences: Boolean = false
|
||||
)
|
||||
|
||||
public class CliOptionProcessingException(message: String, cause: Throwable? = null): RuntimeException(message, cause)
|
||||
|
||||
public trait CommandLineProcessor {
|
||||
public val pluginId: String
|
||||
public val pluginOptions: Collection<CliOption>
|
||||
|
||||
[throws(javaClass<CliOptionProcessingException>())]
|
||||
public fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration)
|
||||
}
|
||||
Reference in New Issue
Block a user