Encode all compiler plugin arguments for Android Extensions in kapt

Commas in option values breaks the option parsing in daemon (KT-20235).
This commit is contained in:
Yan Zhulanow
2017-10-31 11:35:42 +09:00
parent 425d104255
commit 1f65f8bc97
11 changed files with 132 additions and 57 deletions
@@ -30,4 +30,14 @@ interface CommandLineProcessor {
paths.add(value)
put(option, paths)
}
fun CompilerConfiguration.applyOptionsFrom(map: Map<String, List<String>>, pluginOptions: Collection<CliOption>) {
for ((key, values) in map) {
val option = pluginOptions.firstOrNull { it.name == key } ?: continue
for (value in values) {
processOption(option, value, this)
}
}
}
}
-13
View File
@@ -1,13 +0,0 @@
-d
$TEMP_DIR$
-Xplugin=dist/kotlinc/lib/android-extensions-compiler.jar
-P
plugin\:org.jetbrains.kotlin.android\:package=com.myapp
$TESTDATA_DIR$/pluginSimple.kt
$TESTDATA_DIR$/androidPlugin/androidApp.kt
$TESTDATA_DIR$/androidPlugin/androidView.kt
$TESTDATA_DIR$/androidPlugin/androidWidget.kt
$TESTDATA_DIR$/androidPlugin/fakeAppwidgetPackage.kt
$TESTDATA_DIR$/androidPlugin/fakeInputMethodServicePackage.kt
$TESTDATA_DIR$/androidPlugin/fakeOpenglPackage.kt
$TESTDATA_DIR$/androidPlugin/fakeWebkitPackage.kt
-8
View File
@@ -1,8 +0,0 @@
import android.view.*
import android.app.*
import android.widget.*
import kotlinx.android.synthetic.main.layout.*
class MyActivity : Activity() {
{ textView.setText("Some text") }
}
-10
View File
@@ -1,10 +0,0 @@
error: required plugin option not present: org.jetbrains.kotlin.android:variant
Plugin "org.jetbrains.kotlin.android" usage:
variant <name;path> Android build variant (required, multiple)
package <fq name> Application package (required)
experimental true/false Enable experimental features
defaultCacheImplementation hashMap/sparseArray/none
Default cache implementation for module
COMPILATION_ERROR
@@ -398,12 +398,6 @@ public class CliTestGenerated extends AbstractCliTest {
doJvmTest(fileName);
}
@TestMetadata("pluginSimpleUsage.args")
public void testPluginSimpleUsage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/pluginSimpleUsage.args");
doJvmTest(fileName);
}
@TestMetadata("returnAsWhenKey.args")
public void testReturnAsWhenKey() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/returnAsWhenKey.args");
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2017 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.utils
import java.io.ByteArrayInputStream
import java.io.ObjectInputStream
import java.util.*
fun decodePluginOptions(options: String): Map<String, List<String>> {
val map = LinkedHashMap<String, List<String>>()
val decodedBytes = Base64.getDecoder().decode(options)
val bis = ByteArrayInputStream(decodedBytes)
val ois = ObjectInputStream(bis)
val n = ois.readInt()
repeat(n) {
val key = ois.readUTF()
val valueCount = ois.readInt()
val values = mutableListOf<String>()
repeat(valueCount) {
values += ois.readUTF()
}
map[key] = values
}
return map
}
@@ -128,7 +128,7 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
addVariant(sourceSet)
}
return pluginOptions
return wrapPluginOptions(pluginOptions, "configuration")
}
private fun getLayoutDirectories(resDirectories: Collection<File>): List<File> {
@@ -198,7 +198,7 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
addSourceSetAsVariant(variantName)
}
return pluginOptions
return wrapPluginOptions(pluginOptions, "configuration")
}
// Android25ProjectHandler.KaptVariant actually contains BaseVariant, not BaseVariantData
@@ -30,12 +30,12 @@ import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedSourcesDir
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedKotlinSourcesDir
import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.util.*
// apply plugin: 'kotlin-kapt'
@@ -234,9 +234,9 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
androidPlugin
) + androidOptions + mapOf("kapt.kotlin.generated" to kotlinSourcesOutputDir.absolutePath)
pluginOptions += SubpluginOption("apoptions", encodeOptions(apOptions))
pluginOptions += SubpluginOption("apoptions", encodeList(apOptions))
pluginOptions += SubpluginOption("javacArguments", encodeOptions(kaptExtension.getJavacOptions()))
pluginOptions += SubpluginOption("javacArguments", encodeList(kaptExtension.getJavacOptions()))
addMiscOptions(pluginOptions)
@@ -245,19 +245,19 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
private fun Kapt3SubpluginContext.buildAndAddOptionsTo(container: CompilerPluginOptions, aptMode: String) {
val compilerPluginId = getCompilerPluginId()
for (option in buildOptions(aptMode)) {
for (option in wrapPluginOptions(buildOptions(aptMode), "configuration")) {
container.addPluginArgument(compilerPluginId, option.key, option.value)
}
}
fun encodeOptions(options: Map<String, String>): String {
private fun encodeList(options: Map<String, String>): String {
val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os)
oos.writeInt(options.size)
for ((k, v) in options.entries) {
oos.writeUTF(k)
oos.writeUTF(v)
for ((key, value) in options.entries) {
oos.writeUTF(key)
oos.writeUTF(value)
}
oos.flush()
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2017 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.gradle.internal
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.util.*
fun encodePluginOptions(options: Map<String, List<String>>): String {
val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os)
oos.writeInt(options.size)
for ((key, values) in options.entries) {
oos.writeUTF(key)
oos.writeInt(values.size)
for (value in values) {
oos.writeUTF(value)
}
}
oos.flush()
return Base64.getEncoder().encodeToString(os.toByteArray())
}
fun wrapPluginOptions(options: List<SubpluginOption>, newOptionName: String): List<SubpluginOption> {
val groupedOptions = options.groupBy { it.key }.mapValues { opt -> opt.value.map { it.value } }
val encodedOptions = encodePluginOptions(groupedOptions)
val singleOption = SubpluginOption(newOptionName, encodedOptions)
return listOf(singleOption)
}
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.utils.decodePluginOptions
object AndroidConfigurationKeys {
val VARIANT = CompilerConfigurationKey.create<List<String>>("Android build variant")
@@ -59,8 +60,10 @@ class AndroidCommandLineProcessor : CommandLineProcessor {
companion object {
val ANDROID_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.android"
val VARIANT_OPTION = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true)
val PACKAGE_OPTION = CliOption("package", "<fq name>", "Application package")
val CONFIGURATION = CliOption("configuration", "<encoded>", "Encoded configuration", required = false)
val VARIANT_OPTION = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true, required = false)
val PACKAGE_OPTION = CliOption("package", "<fq name>", "Application package", required = false)
val EXPERIMENTAL_OPTION = CliOption("experimental", "true/false", "Enable experimental features", required = false)
val DEFAULT_CACHE_IMPL_OPTION = CliOption(
"defaultCacheImplementation", "hashMap/sparseArray/none", "Default cache implementation for module", required = false)
@@ -72,7 +75,7 @@ class AndroidCommandLineProcessor : CommandLineProcessor {
override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption>
= listOf(VARIANT_OPTION, PACKAGE_OPTION, EXPERIMENTAL_OPTION, DEFAULT_CACHE_IMPL_OPTION)
= listOf(VARIANT_OPTION, PACKAGE_OPTION, EXPERIMENTAL_OPTION, DEFAULT_CACHE_IMPL_OPTION, CONFIGURATION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
@@ -80,6 +83,7 @@ class AndroidCommandLineProcessor : CommandLineProcessor {
PACKAGE_OPTION -> configuration.put(AndroidConfigurationKeys.PACKAGE, value)
EXPERIMENTAL_OPTION -> configuration.put(AndroidConfigurationKeys.EXPERIMENTAL, value)
DEFAULT_CACHE_IMPL_OPTION -> configuration.put(AndroidConfigurationKeys.DEFAULT_CACHE_IMPL, value)
CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
@@ -101,8 +105,8 @@ class AndroidComponentRegistrar : ComponentRegistrar {
}
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val applicationPackage = configuration.get(AndroidConfigurationKeys.PACKAGE)
val variants = configuration.get(AndroidConfigurationKeys.VARIANT)?.mapNotNull { parseVariant(it) } ?: emptyList()
val applicationPackage = configuration.get(AndroidConfigurationKeys.PACKAGE) ?: return
val variants = configuration.get(AndroidConfigurationKeys.VARIANT)?.mapNotNull { parseVariant(it) } ?: return
val isExperimental = configuration.get(AndroidConfigurationKeys.EXPERIMENTAL) == "true"
val globalCacheImpl = parseCacheImplementationType(configuration.get(AndroidConfigurationKeys.DEFAULT_CACHE_IMPL))
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.utils.decodePluginOptions
import java.io.ByteArrayInputStream
import java.io.File
import java.io.ObjectInputStream
@@ -93,6 +94,8 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
companion object {
val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3"
val CONFIGURATION = CliOption("configuration", "<encoded>", "Encoded configuration", required = false)
val SOURCE_OUTPUT_DIR_OPTION: CliOption =
CliOption("sources", "<path>", "Output path for the generated files", required = false)
@@ -145,7 +148,8 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
override val pluginOptions: Collection<CliOption> =
listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, JAVAC_CLI_OPTIONS_OPTION,
CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, APT_MODE_OPTION,
USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION, INCREMENTAL_DATA_OUTPUT_DIR_OPTION)
USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION, INCREMENTAL_DATA_OUTPUT_DIR_OPTION,
CONFIGURATION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
@@ -162,6 +166,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
APT_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_MODE, value)
USE_LIGHT_ANALYSIS_OPTION -> configuration.put(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS, value)
CORRECT_ERROR_TYPES_OPTION -> configuration.put(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES, value)
CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
@@ -172,7 +177,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
private const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context"
}
fun decodeOptions(options: String): Map<String, String> {
private fun decodeList(options: String): Map<String, String> {
val map = LinkedHashMap<String, String>()
val decodedBytes = Base64.getDecoder().decode(options)
@@ -232,8 +237,8 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
return
}
val apOptions = configuration.get(APT_OPTIONS)?.let { decodeOptions(it) } ?: emptyMap()
val javacCliOptions = configuration.get(JAVAC_CLI_OPTIONS)?.let { decodeOptions(it) } ?: emptyMap()
val apOptions = configuration.get(APT_OPTIONS)?.let { decodeList(it) } ?: emptyMap()
val javacCliOptions = configuration.get(JAVAC_CLI_OPTIONS)?.let { decodeList(it) } ?: emptyMap()
sourcesOutputDir.mkdirs()