Load compiler plugins via ServiceLoader

This commit is contained in:
Yan Zhulanow
2014-10-22 17:44:16 +04:00
parent af9c5cc45d
commit e0f1a56b28
@@ -34,60 +34,43 @@ import java.net.URLClassLoader
import java.net.URL import java.net.URL
import java.io.File import java.io.File
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import java.util.ServiceLoader
public object PluginCliParser { public object PluginCliParser {
public val PLUGIN_ARGUMENT_PREFIX: String = "plugin:" public val PLUGIN_ARGUMENT_PREFIX: String = "plugin:"
private class Context(
val arguments: CommonCompilerArguments,
val configuration: CompilerConfiguration,
val classLoader: ClassLoader,
val pluginManifestAttributes: List<Attributes>
)
[platformStatic] [platformStatic]
fun loadPlugins(arguments: CommonCompilerArguments, configuration: CompilerConfiguration) { fun loadPlugins(arguments: CommonCompilerArguments, configuration: CompilerConfiguration) {
val classLoader = URLClassLoader(arguments.pluginClasspaths?.map {File(it).toURI().toURL()}?.copyToArray() ?: array<URL>(), javaClass.getClassLoader()) val classLoader = URLClassLoader(
val pluginManifestAttributes = arguments.pluginClasspaths?.map { arguments.pluginClasspaths
JarFile(it).getManifest()?.getAttributes("org.jetbrains.kotlin.compiler.plugin") ?.map { File(it).toURI().toURL() }
}?.filterNotNull() ?: listOf() ?.copyToArray()
val context = Context(arguments, configuration, classLoader, pluginManifestAttributes) ?: array<URL>(),
context.loadComponentRegistrars() javaClass.getClassLoader()
context.processPluginOptions() )
configuration.addAll(
ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS,
ServiceLoader.load(javaClass<ComponentRegistrar>(), classLoader).toList()
)
processPluginOptions(arguments, configuration, classLoader)
} }
private fun Context.loadComponentRegistrars() { private fun processPluginOptions(
for (attributes in pluginManifestAttributes) { arguments: CommonCompilerArguments,
val registrar = loadComponent<ComponentRegistrar>(attributes, "ComponentRegistrar") configuration: CompilerConfiguration,
if (registrar == null) continue classLoader: ClassLoader
) {
configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, registrar)
}
}
private fun Context.loadComponent<T: Any>(attributes: Attributes, componentName: String): T? {
val processorClassName = attributes.getValue(componentName)
if (processorClassName == null) return null
try {
val processorClass = Class.forName(processorClassName, true, classLoader)
[suppress("UNCHECKED_CAST")]
return processorClass.newInstance() as T
}
catch (e: Throwable) {
throw CliOptionProcessingException("Loading plugin component failed: $componentName=$processorClassName ($e)", e)
}
}
private fun Context.processPluginOptions() {
val optionValuesByPlugin = arguments.pluginOptions?.map { parsePluginOption(it) }?.groupBy { val optionValuesByPlugin = arguments.pluginOptions?.map { parsePluginOption(it) }?.groupBy {
if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}") if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}")
it.pluginId it.pluginId
} ?: mapOf() } ?: mapOf()
val processors = pluginManifestAttributes.map { loadComponent<CommandLineProcessor>(it, "CommandLineProcessor") }.filterNotNull() val commandLineProcessors = ServiceLoader.load(javaClass<CommandLineProcessor>(), classLoader).toList()
for (processor in processors) {
for (processor in commandLineProcessors) {
val declaredOptions = processor.pluginOptions.valuesToMap { it.name } val declaredOptions = processor.pluginOptions.valuesToMap { it.name }
val optionsToValues = MultiMap<CliOption, PluginOptionValue>() val optionsToValues = MultiMap<CliOption, PluginOptionValue>()