Load compiler plugins via ServiceLoader
This commit is contained in:
@@ -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>()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user