Android dependency resolving stuff moved out of KotlinMultiplatformExtension.kt
This commit is contained in:
+178
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.dsl
|
||||||
|
|
||||||
|
import com.android.build.gradle.BaseExtension
|
||||||
|
import com.android.build.gradle.api.AndroidSourceSet
|
||||||
|
import com.android.build.gradle.internal.LoggerWrapper
|
||||||
|
import com.android.build.gradle.internal.publishing.AndroidArtifacts
|
||||||
|
import com.android.sdklib.IAndroidTarget
|
||||||
|
import com.android.sdklib.repository.AndroidSdkHandler
|
||||||
|
import com.android.sdklib.repository.LoggerProgressIndicatorWrapper
|
||||||
|
import com.intellij.openapi.util.Version
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.*
|
||||||
|
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||||
|
import org.gradle.api.artifacts.component.ModuleComponentSelector
|
||||||
|
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||||
|
import org.gradle.api.file.FileSystemLocation
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.forEachVariant
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.reflect.full.findParameterByName
|
||||||
|
|
||||||
|
data class AndroidDependency(
|
||||||
|
val name: String? = null,
|
||||||
|
val jar: File? = null,
|
||||||
|
val source: File? = null,
|
||||||
|
val group: String? = null,
|
||||||
|
val version: String? = null,
|
||||||
|
val collection: Set<File>? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
object AndroidDependencyResolver {
|
||||||
|
private fun getAndroidSdkJar(project: Project): AndroidDependency? {
|
||||||
|
val androidExtension = project.extensions.findByName("android") as BaseExtension? ?: return null
|
||||||
|
val sdkLocation = getClassOrNull("com.android.build.gradle.internal.SdkLocationSourceSet")?.let { sdkLocationSourceSetClass ->
|
||||||
|
val sdkLocationSourceSet = sdkLocationSourceSetClass.kotlin.constructors.firstOrNull()?.let { callable ->
|
||||||
|
callable.findParameterByName("projectRoot")?.let { param ->
|
||||||
|
callable.callBy(mapOf(param to project.rootDir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sdkLocatorClass = getClassOrNull("com.android.build.gradle.internal.SdkLocator")
|
||||||
|
val sdkLocation =
|
||||||
|
sdkLocatorClass?.getMethodOrNull("getSdkLocation", sdkLocationSourceSetClass)?.invoke(sdkLocatorClass, sdkLocationSourceSet)
|
||||||
|
sdkLocation?.javaClass?.getMethodOrNull("getDirectory")?.invoke(sdkLocation) as? File
|
||||||
|
} ?: return null
|
||||||
|
val sdkHandler = AndroidSdkHandler.getInstance(sdkLocation)
|
||||||
|
val logger = LoggerProgressIndicatorWrapper(LoggerWrapper(project.logger))
|
||||||
|
val androidTarget = sdkHandler.getAndroidTargetManager(logger).getTargetFromHashString(androidExtension.compileSdkVersion, logger)
|
||||||
|
return AndroidDependency(
|
||||||
|
androidTarget.fullName,
|
||||||
|
File(androidTarget.getPath(IAndroidTarget.ANDROID_JAR)),
|
||||||
|
File(androidTarget.getPath(IAndroidTarget.SOURCES))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getClassOrNull(s: String) =
|
||||||
|
try {
|
||||||
|
Class.forName(s)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Class<*>.getMethodOrNull(name: String, vararg parameterTypes: Class<*>) =
|
||||||
|
try {
|
||||||
|
getMethod(name, *parameterTypes)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isAndroidPluginCompatible(): Boolean {
|
||||||
|
val version = getClassOrNull("com.android.Version")?.let {
|
||||||
|
try {
|
||||||
|
it.getField("ANDROID_GRADLE_PLUGIN_VERSION").get(null) as String
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} ?: return false
|
||||||
|
return Version.parseVersion(version)?.isOrGreaterThan(3, 6) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAndroidSourceSetDependencies(project: Project): Map<String, List<AndroidDependency>?> {
|
||||||
|
if (!isAndroidPluginCompatible()) return emptyMap()
|
||||||
|
|
||||||
|
data class SourceSetConfigs(val implConfig: Configuration, val compileConfig: Configuration)
|
||||||
|
|
||||||
|
val androidSdkJar = getAndroidSdkJar(project) ?: return emptyMap()
|
||||||
|
val sourceSet2Impl = HashMap<String, SourceSetConfigs>()
|
||||||
|
val allImplConfigs = HashSet<Configuration>()
|
||||||
|
|
||||||
|
project.forEachVariant { variant ->
|
||||||
|
val compileConfig = variant.compileConfiguration
|
||||||
|
variant.sourceSets.filterIsInstance(AndroidSourceSet::class.java).map {
|
||||||
|
val implConfig = project.configurations.getByName(it.implementationConfigurationName)
|
||||||
|
allImplConfigs.add(implConfig)
|
||||||
|
sourceSet2Impl[lowerCamelCaseName("android", it.name)] = SourceSetConfigs(implConfig, compileConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceSet2Impl.mapValues { entry ->
|
||||||
|
val dependencies = findDependencies(allImplConfigs, entry.value.implConfig)
|
||||||
|
|
||||||
|
val selfResolved = dependencies.filterIsInstance<SelfResolvingDependency>().map { AndroidDependency(collection = it.resolve()) }
|
||||||
|
val resolvedExternal = dependencies.filterIsInstance<ExternalModuleDependency>()
|
||||||
|
.flatMap { collectDependencies(it.module, entry.value.compileConfig) }
|
||||||
|
|
||||||
|
val result = (selfResolved + resolvedExternal + androidSdkJar).toMutableList()
|
||||||
|
|
||||||
|
if (entry.key == "androidMain") {
|
||||||
|
// this is a terrible hack, but looks like the only way, other than proper support via light-classes
|
||||||
|
val task = project.tasks.findByName("processDebugResources")
|
||||||
|
getClassOrNull("com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask")?.let { linkAppClass ->
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val rClassOutputJar =
|
||||||
|
linkAppClass.getMethodOrNull("getRClassOutputJar")?.invoke(task) as Provider<FileSystemLocation>?
|
||||||
|
rClassOutputJar?.orNull?.asFile?.let { result += AndroidDependency("R.jar", it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
private fun collectDependencies(
|
||||||
|
module: ModuleIdentifier,
|
||||||
|
compileClasspathConf: Configuration
|
||||||
|
): List<AndroidDependency> {
|
||||||
|
val viewConfig: (ArtifactView.ViewConfiguration) -> Unit = { config ->
|
||||||
|
config.attributes { it.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.JAR.type) }
|
||||||
|
config.isLenient = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedArtifacts = compileClasspathConf.incoming.artifactView(viewConfig).artifacts.mapNotNull {
|
||||||
|
val componentIdentifier = it.id.componentIdentifier as? ModuleComponentIdentifier ?: return@mapNotNull null
|
||||||
|
val id = componentIdentifier.moduleIdentifier ?: return@mapNotNull null
|
||||||
|
id to AndroidDependency(id.name, it.file, null, id.group, componentIdentifier.version)
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
val resolutionResults = compileClasspathConf.incoming.resolutionResult.allComponents.mapNotNull {
|
||||||
|
val id = it.moduleVersion?.module ?: return@mapNotNull null
|
||||||
|
id to it
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
val deps = HashSet<ModuleIdentifier>().also { doCollectDependencies(listOf(module), resolutionResults, it) }
|
||||||
|
return deps.mapNotNull { resolvedArtifacts[it] }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
private tailrec fun doCollectDependencies(
|
||||||
|
modules: List<ModuleIdentifier>,
|
||||||
|
resolutionResults: Map<ModuleIdentifier, ResolvedComponentResult>,
|
||||||
|
result: MutableSet<ModuleIdentifier>
|
||||||
|
) {
|
||||||
|
if (modules.isEmpty()) return
|
||||||
|
val newModules = modules.filter { result.add(it) }.mapNotNull { resolutionResults[it] }.flatMap { it.dependencies }
|
||||||
|
.mapNotNull { (it.requested as? ModuleComponentSelector)?.moduleIdentifier }
|
||||||
|
doCollectDependencies(newModules, resolutionResults, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findDependencies(implConfigs: Set<Configuration>, conf: Configuration): Set<Dependency> {
|
||||||
|
return HashSet<Dependency>().also { doFindDependencies(implConfigs, listOf(conf), it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun doFindDependencies(
|
||||||
|
implConfigs: Set<Configuration>, configs: List<Configuration>, result: MutableSet<Dependency>,
|
||||||
|
visited: MutableSet<Configuration> = HashSet()
|
||||||
|
) {
|
||||||
|
if (configs.isEmpty()) return
|
||||||
|
result.addAll(configs.flatMap { it.dependencies })
|
||||||
|
doFindDependencies(implConfigs, configs.flatMap { it.extendsFrom }.filter { it !in implConfigs && visited.add(it) }, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-170
@@ -5,37 +5,21 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.dsl
|
package org.jetbrains.kotlin.gradle.dsl
|
||||||
|
|
||||||
import com.android.build.gradle.BaseExtension
|
|
||||||
import com.android.build.gradle.api.AndroidSourceSet
|
|
||||||
import com.android.build.gradle.internal.LoggerWrapper
|
|
||||||
import com.android.build.gradle.internal.publishing.AndroidArtifacts
|
|
||||||
import com.android.build.gradle.internal.publishing.AndroidArtifacts.ARTIFACT_TYPE
|
|
||||||
import com.android.sdklib.IAndroidTarget
|
|
||||||
import com.android.sdklib.repository.AndroidSdkHandler
|
|
||||||
import com.android.sdklib.repository.LoggerProgressIndicatorWrapper
|
|
||||||
import com.intellij.openapi.util.Version
|
|
||||||
import groovy.lang.Closure
|
import groovy.lang.Closure
|
||||||
import org.gradle.api.InvalidUserCodeException
|
import org.gradle.api.InvalidUserCodeException
|
||||||
import org.gradle.api.NamedDomainObjectCollection
|
import org.gradle.api.NamedDomainObjectCollection
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.*
|
|
||||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
|
||||||
import org.gradle.api.artifacts.component.ModuleComponentSelector
|
|
||||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
|
||||||
import org.gradle.api.file.FileSystemLocation
|
|
||||||
import org.gradle.api.provider.Provider
|
|
||||||
import org.gradle.util.ConfigureUtil
|
import org.gradle.util.ConfigureUtil
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTests
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetsContainerWithPresets
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.reflect.full.findParameterByName
|
|
||||||
|
|
||||||
open class KotlinMultiplatformExtension :
|
open class KotlinMultiplatformExtension :
|
||||||
KotlinProjectExtension(),
|
KotlinProjectExtension(),
|
||||||
KotlinTargetContainerWithPresetFunctions,
|
KotlinTargetContainerWithPresetFunctions,
|
||||||
KotlinTargetContainerWithNativeShortcuts
|
KotlinTargetContainerWithNativeShortcuts {
|
||||||
{
|
|
||||||
override lateinit var presets: NamedDomainObjectCollection<KotlinTargetPreset<*>>
|
override lateinit var presets: NamedDomainObjectCollection<KotlinTargetPreset<*>>
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
@@ -72,155 +56,9 @@ open class KotlinMultiplatformExtension :
|
|||||||
KotlinSoftwareComponentWithCoordinatesAndPublication("kotlin", targets)
|
KotlinSoftwareComponentWithCoordinatesAndPublication("kotlin", targets)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class AndroidDependency(
|
@Suppress("unused")
|
||||||
val name: String? = null,
|
fun getAndroidSourceSetDependencies(project: Project) =
|
||||||
val jar: File? = null,
|
AndroidDependencyResolver.getAndroidSourceSetDependencies(project)
|
||||||
val source: File? = null,
|
|
||||||
val group: String? = null,
|
|
||||||
val version: String? = null,
|
|
||||||
val collection: Set<File>? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getAndroidSdkJar(project: Project): AndroidDependency? {
|
|
||||||
val androidExtension = project.extensions.findByName("android") as BaseExtension? ?: return null
|
|
||||||
val sdkLocation = getClassOrNull("com.android.build.gradle.internal.SdkLocationSourceSet")?.let { sdkLocationSourceSetClass ->
|
|
||||||
val sdkLocationSourceSet = sdkLocationSourceSetClass.kotlin.constructors.firstOrNull()?.let { callable ->
|
|
||||||
callable.findParameterByName("projectRoot")?.let { param ->
|
|
||||||
callable.callBy(mapOf(param to project.rootDir))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val sdkLocatorClass = getClassOrNull("com.android.build.gradle.internal.SdkLocator")
|
|
||||||
val sdkLocation =
|
|
||||||
sdkLocatorClass?.getMethodOrNull("getSdkLocation", sdkLocationSourceSetClass)?.invoke(sdkLocatorClass, sdkLocationSourceSet)
|
|
||||||
sdkLocation?.javaClass?.getMethodOrNull("getDirectory")?.invoke(sdkLocation) as? File
|
|
||||||
} ?: return null
|
|
||||||
val sdkHandler = AndroidSdkHandler.getInstance(sdkLocation)
|
|
||||||
val logger = LoggerProgressIndicatorWrapper(LoggerWrapper(project.logger))
|
|
||||||
val androidTarget = sdkHandler.getAndroidTargetManager(logger).getTargetFromHashString(androidExtension.compileSdkVersion, logger)
|
|
||||||
return AndroidDependency(
|
|
||||||
androidTarget.fullName,
|
|
||||||
File(androidTarget.getPath(IAndroidTarget.ANDROID_JAR)),
|
|
||||||
File(androidTarget.getPath(IAndroidTarget.SOURCES))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getClassOrNull(s: String) =
|
|
||||||
try {
|
|
||||||
Class.forName(s)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Class<*>.getMethodOrNull(name: String, vararg parameterTypes: Class<*>) =
|
|
||||||
try {
|
|
||||||
getMethod(name, *parameterTypes)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isAndroidPluginCompatible(): Boolean {
|
|
||||||
val version = getClassOrNull("com.android.Version")?.let {
|
|
||||||
try {
|
|
||||||
it.getField("ANDROID_GRADLE_PLUGIN_VERSION").get(null) as String
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} ?: return false
|
|
||||||
return Version.parseVersion(version)?.isOrGreaterThan(3, 6) ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAndroidSourceSetDependencies(project: Project): Map<String, List<AndroidDependency>?> {
|
|
||||||
if (!isAndroidPluginCompatible()) return emptyMap()
|
|
||||||
|
|
||||||
data class SourceSetConfigs(val implConfig: Configuration, val compileConfig: Configuration)
|
|
||||||
|
|
||||||
val androidSdkJar = getAndroidSdkJar(project) ?: return emptyMap()
|
|
||||||
val sourceSet2Impl = HashMap<String, SourceSetConfigs>()
|
|
||||||
val allImplConfigs = HashSet<Configuration>()
|
|
||||||
|
|
||||||
project.forEachVariant { variant ->
|
|
||||||
val compileConfig = variant.compileConfiguration
|
|
||||||
variant.sourceSets.filterIsInstance(AndroidSourceSet::class.java).map {
|
|
||||||
val implConfig = project.configurations.getByName(it.implementationConfigurationName)
|
|
||||||
allImplConfigs.add(implConfig)
|
|
||||||
sourceSet2Impl[lowerCamelCaseName("android", it.name)] = SourceSetConfigs(implConfig, compileConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sourceSet2Impl.mapValues { entry ->
|
|
||||||
val dependencies = findDependencies(allImplConfigs, entry.value.implConfig)
|
|
||||||
|
|
||||||
val selfResolved = dependencies.filterIsInstance<SelfResolvingDependency>().map { AndroidDependency(collection = it.resolve()) }
|
|
||||||
val resolvedExternal = dependencies.filterIsInstance<ExternalModuleDependency>()
|
|
||||||
.flatMap { collectDependencies(it.module, entry.value.compileConfig) }
|
|
||||||
|
|
||||||
val result = (selfResolved + resolvedExternal + androidSdkJar).toMutableList()
|
|
||||||
|
|
||||||
if (entry.key == "androidMain") {
|
|
||||||
// this is a terrible hack, but looks like the only way, other than proper support via light-classes
|
|
||||||
val task = project.tasks.findByName("processDebugResources")
|
|
||||||
getClassOrNull("com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask")?.let { linkAppClass ->
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
val rClassOutputJar =
|
|
||||||
linkAppClass.getMethodOrNull("getRClassOutputJar")?.invoke(task) as Provider<FileSystemLocation>?
|
|
||||||
rClassOutputJar?.orNull?.asFile?.let { result += AndroidDependency("R.jar", it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}.toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UnstableApiUsage")
|
|
||||||
private fun collectDependencies(
|
|
||||||
module: ModuleIdentifier,
|
|
||||||
compileClasspathConf: Configuration
|
|
||||||
): List<AndroidDependency> {
|
|
||||||
val viewConfig: (ArtifactView.ViewConfiguration) -> Unit = { config ->
|
|
||||||
config.attributes { it.attribute(ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.JAR.type) }
|
|
||||||
config.isLenient = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val resolvedArtifacts = compileClasspathConf.incoming.artifactView(viewConfig).artifacts.mapNotNull {
|
|
||||||
val componentIdentifier = it.id.componentIdentifier as? ModuleComponentIdentifier ?: return@mapNotNull null
|
|
||||||
val id = componentIdentifier.moduleIdentifier ?: return@mapNotNull null
|
|
||||||
id to AndroidDependency(id.name, it.file, null, id.group, componentIdentifier.version)
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
val resolutionResults = compileClasspathConf.incoming.resolutionResult.allComponents.mapNotNull {
|
|
||||||
val id = it.moduleVersion?.module ?: return@mapNotNull null
|
|
||||||
id to it
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
val deps = HashSet<ModuleIdentifier>().also { doCollectDependencies(listOf(module), resolutionResults, it) }
|
|
||||||
return deps.mapNotNull { resolvedArtifacts[it] }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UnstableApiUsage")
|
|
||||||
private tailrec fun doCollectDependencies(
|
|
||||||
modules: List<ModuleIdentifier>,
|
|
||||||
resolutionResults: Map<ModuleIdentifier, ResolvedComponentResult>,
|
|
||||||
result: MutableSet<ModuleIdentifier>
|
|
||||||
) {
|
|
||||||
if (modules.isEmpty()) return
|
|
||||||
val newModules = modules.filter { result.add(it) }.mapNotNull { resolutionResults[it] }.flatMap { it.dependencies }
|
|
||||||
.mapNotNull { (it.requested as? ModuleComponentSelector)?.moduleIdentifier }
|
|
||||||
doCollectDependencies(newModules, resolutionResults, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findDependencies(implConfigs: Set<Configuration>, conf: Configuration): Set<Dependency> {
|
|
||||||
return HashSet<Dependency>().also { doFindDependencies(implConfigs, listOf(conf), it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private tailrec fun doFindDependencies(
|
|
||||||
implConfigs: Set<Configuration>, configs: List<Configuration>, result: MutableSet<Dependency>,
|
|
||||||
visited: MutableSet<Configuration> = HashSet()
|
|
||||||
) {
|
|
||||||
if (configs.isEmpty()) return
|
|
||||||
result.addAll(configs.flatMap { it.dependencies })
|
|
||||||
doFindDependencies(implConfigs, configs.flatMap { it.extendsFrom }.filter { it !in implConfigs && visited.add(it) }, result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun KotlinTarget.isProducedFromPreset(kotlinTargetPreset: KotlinTargetPreset<*>): Boolean =
|
internal fun KotlinTarget.isProducedFromPreset(kotlinTargetPreset: KotlinTargetPreset<*>): Boolean =
|
||||||
|
|||||||
Reference in New Issue
Block a user