Check supportv4 library presence on the spot

This commit is contained in:
Yan Zhulanow
2015-08-20 15:35:52 +03:00
parent de59b79deb
commit a2096ab0be
8 changed files with 42 additions and 85 deletions
@@ -19,50 +19,34 @@ package org.jetbrains.kotlin.android
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import org.gradle.api
import com.android.build.gradle.BaseExtension
import java.io.File
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
public class AndroidSubplugin : KotlinGradleSubplugin {
override fun getExtraArguments(project: api.Project, task: AbstractCompile): List<SubpluginOption>? {
val androidExtension = project.getExtensions().getByName("android") as? BaseExtension
val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return null
if (androidExtension == null) return null
val sourceSets = androidExtension.getSourceSets()
val sourceSets = androidExtension.sourceSets
val mainSourceSet = sourceSets.getByName("main")
val resourceDirs = mainSourceSet.getRes().getSrcDirs()
val manifestFile = mainSourceSet.getManifest().getSrcFile()
val compileDependencies = project.getConfigurations().getByName("compile").getFiles()
val supportV4 = compileDependencies?.filter { it.name.startsWith("support-v4-") }?.isNotEmpty() ?: false
val supportV4Property = if (supportV4) "true" else "false"
val resourceDirs = mainSourceSet.res.srcDirs
val manifestFile = mainSourceSet.manifest.srcFile
if (resourceDirs.isNotEmpty()) {
val resourceDirOptions = resourceDirs.map { resourceDir ->
resourceDir.listFiles { it.isDirectory() && it.name.startsWith("layout") }?.forEach { task.source(it) }
SubpluginOption("androidRes", resourceDir.getAbsolutePath())
resourceDir.listFiles { it.isDirectory && it.name.startsWith("layout") }?.forEach { task.source(it) }
SubpluginOption("androidRes", resourceDir.absolutePath)
}
return listOf(
SubpluginOption("androidManifest", manifestFile.getAbsolutePath()),
SubpluginOption("supportV4", supportV4Property)
) + resourceDirOptions
return listOf(SubpluginOption("androidManifest", manifestFile.absolutePath)) + resourceDirOptions
}
return null
}
override fun getPluginName(): String {
return "org.jetbrains.kotlin.android"
}
override fun getPluginName() = "org.jetbrains.kotlin.android"
override fun getGroupName(): String {
return "org.jetbrains.kotlin"
}
override fun getGroupName() = "org.jetbrains.kotlin"
override fun getArtifactName(): String {
return "kotlin-android-extensions"
}
override fun getArtifactName() = "kotlin-android-extensions"
}
@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.psi.JetFile
public object AndroidConfigurationKeys {
public val ANDROID_RES_PATH: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create<List<String>>("android resources search path")
public val ANDROID_MANIFEST: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("android manifest file")
public val SUPPORT_V4: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("'true' if compiled with support-v4 library")
}
public class AndroidCommandLineProcessor : CommandLineProcessor {
@@ -47,12 +46,11 @@ public class AndroidCommandLineProcessor : CommandLineProcessor {
public val RESOURCE_PATH_OPTION: CliOption = CliOption("androidRes", "<path>", "Android resources path", allowMultipleOccurrences = true)
public val MANIFEST_FILE_OPTION: CliOption = CliOption("androidManifest", "<path>", "Android manifest file")
public val SUPPORT_V4_OPTION: CliOption = CliOption("supportV4", "<path>", "Support android-v4 library", required = false)
}
override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> = listOf(RESOURCE_PATH_OPTION, MANIFEST_FILE_OPTION, SUPPORT_V4_OPTION)
override val pluginOptions: Collection<CliOption> = listOf(RESOURCE_PATH_OPTION, MANIFEST_FILE_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
@@ -62,7 +60,6 @@ public class AndroidCommandLineProcessor : CommandLineProcessor {
configuration.put(AndroidConfigurationKeys.ANDROID_RES_PATH, paths)
}
MANIFEST_FILE_OPTION -> configuration.put(AndroidConfigurationKeys.ANDROID_MANIFEST, value)
SUPPORT_V4_OPTION -> configuration.put(AndroidConfigurationKeys.SUPPORT_V4, value)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
@@ -80,10 +77,9 @@ public class AndroidComponentRegistrar : ComponentRegistrar {
public override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val androidResPath = configuration.get(AndroidConfigurationKeys.ANDROID_RES_PATH)
val androidManifest = configuration.get(AndroidConfigurationKeys.ANDROID_MANIFEST)
val supportV4 = configuration.get(AndroidConfigurationKeys.SUPPORT_V4) ?: "false"
if (androidResPath != null && androidManifest != null) {
val xmlProcessor = CliSyntheticFileGenerator(project, androidManifest, androidResPath, supportV4 == "true")
val xmlProcessor = CliSyntheticFileGenerator(project, androidManifest, androidResPath)
project.registerService(javaClass<SyntheticFileGenerator>(), xmlProcessor)
project.registerService(javaClass<AndroidLayoutXmlFileManager>(), CliAndroidLayoutXmlFileManager(project, androidManifest, androidResPath))
@@ -30,19 +30,15 @@ import kotlin.properties.Delegates
public open class CliSyntheticFileGenerator(
project: Project,
private val manifestPath: String,
private val resDirectories: List<String>,
private val supportV4: Boolean
private val resDirectories: List<String>
) : SyntheticFileGenerator(project) {
private val javaPsiFacade: JavaPsiFacade by lazy { JavaPsiFacade.getInstance(project) }
private val projectScope: GlobalSearchScope by lazy { GlobalSearchScope.allScope(project) }
private val cachedJetFiles by lazy {
generateSyntheticJetFiles(generateSyntheticFiles(true, projectScope))
}
override fun supportV4(): Boolean {
return supportV4
val supportV4 = supportV4Available(javaPsiFacade, projectScope)
generateSyntheticJetFiles(generateSyntheticFiles(true, projectScope, supportV4))
}
override val layoutXmlFileManager: CliAndroidLayoutXmlFileManager by Delegates.lazy {
@@ -39,12 +39,14 @@ public abstract class SyntheticFileGenerator(protected val project: Project) {
public abstract val layoutXmlFileManager: AndroidLayoutXmlFileManager
protected abstract fun supportV4(): Boolean
public abstract fun getSyntheticFiles(): List<JetFile>
protected fun generateSyntheticFiles(generateCommonFiles: Boolean = true, scope: GlobalSearchScope): List<AndroidSyntheticFile> {
val commonFiles = if (generateCommonFiles) generateCommonFiles() else listOf()
protected fun generateSyntheticFiles(
generateCommonFiles: Boolean,
scope: GlobalSearchScope,
supportV4: Boolean
): List<AndroidSyntheticFile> {
val commonFiles = if (generateCommonFiles) generateCommonFiles(supportV4) else listOf()
return layoutXmlFileManager.getLayoutXmlFiles().flatMap { entry ->
val files = entry.getValue()
@@ -52,20 +54,22 @@ public abstract class SyntheticFileGenerator(protected val project: Project) {
val layoutName = entry.getKey()
val mainLayoutFile = renderMainLayoutFile(layoutName, resources)
val mainLayoutFile = renderMainLayoutFile(layoutName, resources, supportV4)
val viewLayoutFile = renderViewLayoutFile(layoutName, resources)
listOf(mainLayoutFile, viewLayoutFile)
}.filterNotNull() + commonFiles
}
private fun generateCommonFiles(): List<AndroidSyntheticFile> {
private fun generateCommonFiles(supportV4: Boolean): List<AndroidSyntheticFile> {
val renderSyntheticFile = renderSyntheticFile("clearCache") {
writePackage(AndroidConst.SYNTHETIC_PACKAGE)
writeAndroidImports()
writeClearCacheFunction(AndroidConst.ACTIVITY_FQNAME)
writeClearCacheFunction(AndroidConst.FRAGMENT_FQNAME)
if (supportV4()) writeClearCacheFunction(AndroidConst.SUPPORT_FRAGMENT_FQNAME)
if (supportV4) {
writeClearCacheFunction(AndroidConst.SUPPORT_FRAGMENT_FQNAME)
}
}
val clearCacheFile = renderSyntheticFile
@@ -74,11 +78,10 @@ public abstract class SyntheticFileGenerator(protected val project: Project) {
protected abstract fun extractLayoutResources(files: List<PsiFile>, scope: GlobalSearchScope): List<AndroidResource>
private fun renderMainLayoutFile(layoutName: String, resources: List<AndroidResource>): AndroidSyntheticFile {
return renderLayoutFile(layoutName + AndroidConst.LAYOUT_POSTFIX,
escapeAndroidIdentifier(layoutName), resources) {
private fun renderMainLayoutFile(layoutName: String, resources: List<AndroidResource>, supportV4: Boolean): AndroidSyntheticFile {
return renderLayoutFile(layoutName + AndroidConst.LAYOUT_POSTFIX, escapeAndroidIdentifier(layoutName), resources) {
val properties = it.mainProperties.toArrayList()
if (supportV4()) properties.addAll(it.mainPropertiesForSupportV4)
if (supportV4) properties.addAll(it.mainPropertiesForSupportV4)
properties
}
}
@@ -155,6 +158,10 @@ public abstract class SyntheticFileGenerator(protected val project: Project) {
return null
}
protected fun supportV4Available(javaPsiFacade: JavaPsiFacade, scope: GlobalSearchScope): Boolean {
return javaPsiFacade.findClasses(AndroidConst.SUPPORT_FRAGMENT_FQNAME, scope).isNotEmpty()
}
protected fun filterDuplicates(resources: List<AndroidResource>): List<AndroidResource> {
val resourceMap = linkedMapOf<String, AndroidResource>()
val resourcesToExclude = hashSetOf<String>()
@@ -47,9 +47,9 @@ class CliSyntheticFileGeneratorForConversionTest(
project: Project,
manifestPath: String,
resDirectories: List<String>,
supportV4: Boolean
) : CliSyntheticFileGenerator(project, manifestPath, resDirectories, supportV4) {
fun gen(scope: GlobalSearchScope) = generateSyntheticFiles(false, scope)
private val supportV4: Boolean
) : CliSyntheticFileGenerator(project, manifestPath, resDirectories) {
fun gen(scope: GlobalSearchScope) = generateSyntheticFiles(false, scope, supportV4)
}
fun UsefulTestCase.createAndroidTestEnvironment(
@@ -61,7 +61,7 @@ fun UsefulTestCase.createAndroidTestEnvironment(
configuration.put(AndroidConfigurationKeys.ANDROID_RES_PATH, resPaths)
configuration.put(AndroidConfigurationKeys.ANDROID_MANIFEST, manifestPath)
val myEnvironment = KotlinCoreEnvironment.createForTests(getTestRootDisposable()!!, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val myEnvironment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val project = myEnvironment.project
val declarationsProvider = AndroidTestExternalDeclarationsProvider(project, resPaths, manifestPath, supportV4)
@@ -72,5 +72,5 @@ fun UsefulTestCase.createAndroidTestEnvironment(
}
fun getResPaths(path: String): List<String> {
return File(path).listFiles { it.name.startsWith("res") && it.isDirectory() }!!.map { "$path${it.name}/" }
return File(path).listFiles { it.name.startsWith("res") && it.isDirectory }!!.map { "$path${it.name}/" }
}
@@ -23,7 +23,6 @@ import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider.Result
import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.android.synthetic.idea.AndroidPsiTreeChangePreprocessor
import org.jetbrains.kotlin.android.synthetic.idea.AndroidXmlVisitor
import org.jetbrains.kotlin.android.synthetic.parseAndroidResource
@@ -33,23 +32,16 @@ import org.jetbrains.kotlin.psi.JetFile
class IDESyntheticFileGenerator(val module: Module) : SyntheticFileGenerator(module.project) {
private val supportV4: Boolean
private val javaPsiFacade: JavaPsiFacade by lazy { JavaPsiFacade.getInstance(module.project) }
private val moduleScope: GlobalSearchScope by lazy { module.getModuleWithDependenciesAndLibrariesScope(false) }
private val cachedJetFiles: CachedValue<List<JetFile>> by lazy {
cachedValue {
Result.create(generateSyntheticJetFiles(generateSyntheticFiles(true, moduleScope)), psiTreeChangePreprocessor)
val supportV4 = supportV4Available(javaPsiFacade, moduleScope)
Result.create(generateSyntheticJetFiles(generateSyntheticFiles(true, moduleScope, supportV4)), psiTreeChangePreprocessor)
}
}
init {
supportV4 = javaPsiFacade.findClasses(AndroidConst.SUPPORT_FRAGMENT_FQNAME, moduleScope).isNotEmpty()
}
override fun supportV4() = supportV4
override val layoutXmlFileManager: IDEAndroidLayoutXmlFileManager = IDEAndroidLayoutXmlFileManager(module)
private val psiTreeChangePreprocessor by lazy {
@@ -31,7 +31,7 @@ public abstract class AbstractParserResultEqualityTest : KotlinAndroidTestCase()
"$path${it.name}/"
}
val cliParser = CliSyntheticFileGenerator(project, "$path../AndroidManifest.xml", resDirs, false)
val cliParser = CliSyntheticFileGenerator(project, "$path../AndroidManifest.xml", resDirs)
val ideParser = IDESyntheticFileGenerator(ModuleManager.getInstance(project).getModules()[0])
val cliResult = cliParser.getSyntheticFiles().joinToString("\n\n")
@@ -23,9 +23,6 @@ import org.jetbrains.jps.model.module.JpsModule
import java.io.File
import org.jetbrains.jps.android.AndroidJpsUtil
import com.intellij.util.PathUtil
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsLibraryDependency
import org.jetbrains.jps.model.module.JpsModuleDependency
public class KotlinAndroidJpsPlugin : KotlinJpsCompilerArgumentsProvider {
override fun getExtraArguments(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List<String> {
@@ -33,27 +30,13 @@ public class KotlinAndroidJpsPlugin : KotlinJpsCompilerArgumentsProvider {
val pluginId = ANDROID_COMPILER_PLUGIN_ID
val resPath = getAndroidResPath(module)
val manifestFile = getAndroidManifest(module)
val supportV4 = if (isSupportV4LibraryAttached(module)) "true" else "false"
return if (resPath != null && manifestFile != null) listOf(
getPluginOptionString(pluginId, RESOURCE_PATH_OPTION_NAME, resPath),
getPluginOptionString(pluginId, MANIFEST_FILE_OPTION_NAME, manifestFile),
getPluginOptionString(pluginId, SUPPORT_V4_OPTION_NAME, supportV4))
getPluginOptionString(pluginId, MANIFEST_FILE_OPTION_NAME, manifestFile))
else listOf()
}
private fun isSupportV4LibraryAttached(module: JpsModule): Boolean {
return module.getDependenciesList().getDependencies().any { dep ->
when (dep) {
is JpsLibraryDependency ->
dep.getLibrary()?.getFiles(JpsOrderRootType.COMPILED)?.any {
it.name.startsWith("support-v4") && it.extension.toUpperCase() == "JAR"
} ?: false
else -> false
}
}
}
override fun getClasspath(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List<String> {
val inJar = File(PathUtil.getJarPathForClass(javaClass)).isFile()
val manifestFile = getAndroidManifest(moduleBuildTarget.getModule())
@@ -88,7 +71,6 @@ public class KotlinAndroidJpsPlugin : KotlinJpsCompilerArgumentsProvider {
private val RESOURCE_PATH_OPTION_NAME = "androidRes"
private val MANIFEST_FILE_OPTION_NAME = "androidManifest"
private val SUPPORT_V4_OPTION_NAME = "supportV4"
private fun getPluginOptionString(pluginId: String, key: String, value: String): String {
return "plugin:$pluginId:$key=$value"