diff options
author | Kamil Doległo <kamilok1965@interia.pl> | 2020-05-20 12:05:26 +0200 |
---|---|---|
committer | Paweł Marks <Kordyjan@users.noreply.github.com> | 2020-06-15 13:15:30 +0200 |
commit | f3baf10b4c882230d382bfcdd94163d070bd0e25 (patch) | |
tree | 128b63b10f05242cfce88da6714d9e04987b5651 /runners/gradle-plugin/src/main/kotlin/org/jetbrains | |
parent | 645e02fb42bbf1cd3ee2773a014ea1e553e09229 (diff) | |
download | dokka-f3baf10b4c882230d382bfcdd94163d070bd0e25.tar.gz dokka-f3baf10b4c882230d382bfcdd94163d070bd0e25.tar.bz2 dokka-f3baf10b4c882230d382bfcdd94163d070bd0e25.zip |
Rework dokka configuration and Gradle plugin
Diffstat (limited to 'runners/gradle-plugin/src/main/kotlin/org/jetbrains')
7 files changed, 176 insertions, 214 deletions
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt index c69c6f67..44a0635f 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt @@ -1,9 +1,5 @@ package org.jetbrains.dokka.gradle -import com.android.build.gradle.* -import com.android.build.gradle.api.BaseVariant -import com.android.builder.core.BuilderConstants -import org.gradle.api.NamedDomainObjectCollection import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.UnknownDomainObjectException @@ -13,57 +9,60 @@ import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.jetbrains.dokka.ReflectDsl -import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension -import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.io.File import java.io.Serializable class ConfigurationExtractor(private val project: Project) { - fun extractConfiguration(targetName: String, variantName: String?) = - extractFromKotlinProject(targetName, variantName) - - fun extractFromKotlinProject(sourceSetName: String, variantName: String?): PlatformData? { + fun extractConfiguration(sourceSetName: String): PlatformData? { val projectExtension = project.extensions.getByType(KotlinProjectExtension::class.java) val sourceSet = projectExtension.sourceSets.findByName(sourceSetName) ?: run { project.logger.error("No source set with name '$sourceSetName' found"); return null } val compilation = when (projectExtension) { - is KotlinMultiplatformExtension -> projectExtension.targets.flatMap { it.compilations } - .find { it.kotlinSourceSets.contains(sourceSet) } + is KotlinMultiplatformExtension -> { + val targets = projectExtension.targets.flatMap { it.compilations } + targets.find { it.name == sourceSetName } ?: targets.find { it.kotlinSourceSets.contains(sourceSet) } + } is KotlinSingleTargetExtension -> projectExtension.target.compilations.find { it.kotlinSourceSets.contains(sourceSet) } else -> null - } ?: run { project.logger.error("No compilation found for set with name '$sourceSetName'"); return null } + } + + val sourceRoots = sourceSet.sourceFiles + val classpath = compilation?.classpath + ?: sourceRoots + sourceSet.allParentSourceFiles() - val classpath = compilation.compileDependencyFiles.files.filter { it.exists() } - val dependencies = (compilation.allKotlinSourceSets - sourceSet).flatMap { it.kotlin.sourceDirectories } return PlatformData( sourceSetName, - classpath, - sourceSet.kotlin.sourceDirectories.filter { it.exists() }.toList(), - dependencies, - sourceSet.dependsOn.map { it.name }, - compilation.target.targetName + classpath.filter { it.exists() }, + sourceRoots, + sourceSet.dependsOn.map { it.name }, + compilation?.target?.platformType?.name ?: "common" ) } + private fun KotlinSourceSet.allParentSourceFiles(): List<File> = + sourceFiles + dependsOn.flatMap { it.allParentSourceFiles() } + fun extractFromJavaPlugin(): PlatformData? = project.convention.findPlugin(JavaPluginConvention::class.java) ?.run { sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME)?.allSource?.srcDirs } - ?.let { PlatformData(null, emptyList(), it.toList(), emptyList(), emptyList(), "") } + ?.let { PlatformData(null, emptyList(), it.toList(), emptyList(), "") } - fun extractFromKotlinTasks(passName: String, kotlinTasks: List<Task>): PlatformData? = + fun extractFromKotlinTasks(kotlinTasks: List<Task>): List<PlatformData> = try { - kotlinTasks.find { it.toString() == passName }?.let { extractFromKotlinTask(it) } + kotlinTasks.map { extractFromKotlinTask(it) } } catch (e: Throwable) { when (e) { is UnknownDomainObjectException, is NoClassDefFoundError, is ClassNotFoundException -> - extractFromKotlinTasksTheHardWay(passName, kotlinTasks) + listOfNotNull(extractFromKotlinTasksTheHardWay(kotlinTasks)) else -> throw e } } @@ -80,18 +79,17 @@ class ConfigurationExtractor(private val project: Project) { .flatMap { it.compilations }.firstOrNull { it.compileKotlinTask == task } else -> throw e } - }.let { + }.let { compilation -> PlatformData( task.name, - getClasspath(it), - getSourceSet(it), - getDependentSourceSetRoots(it), - getDependentSourceSet(it).map { it.name }, - it?.platformType?.toString() ?: "" + compilation?.classpath.orEmpty(), + compilation?.sourceFiles.orEmpty(), + compilation?.dependentSourceSets?.map { it.name }.orEmpty(), + compilation?.platformType?.toString() ?: "" ) } - private fun extractFromKotlinTasksTheHardWay(passName: String, kotlinTasks: List<Task>): PlatformData? { + private fun extractFromKotlinTasksTheHardWay(kotlinTasks: List<Task>): PlatformData? { val allClasspath = mutableSetOf<File>() var allClasspathFileCollection: FileCollection = project.files() val allSourceRoots = mutableSetOf<File>() @@ -128,93 +126,41 @@ class ConfigurationExtractor(private val project: Project) { } classpath.addAll(project.files(allClasspath).toList()) - return PlatformData(null, classpath, allSourceRoots.toList(), emptyList(), emptyList(),"") + return PlatformData(null, classpath, allSourceRoots.toList(), emptyList(), "") } - private fun getSourceSet(target: KotlinTarget, variantName: String? = null): List<File> = - if (variantName != null) - getSourceSet(getCompilation(target, variantName)) - else - getSourceSet(getMainCompilation(target)) - - private fun getClasspath(target: KotlinTarget, variantName: String? = null): List<File> = - if (target.isAndroidTarget()) { - if (variantName != null) - getClasspathFromAndroidTask(getCompilation(target, variantName)) - else - getClasspathFromAndroidTask(getMainCompilation(target)) - } else { - getClasspath(getMainCompilation(target)) - } - - private fun getSourceSet(compilation: KotlinCompilation<*>?): List<File> = compilation - ?.kotlinSourceSets - ?.flatMap { it.kotlin.sourceDirectories } - ?.filter { it.exists() } - .orEmpty() + private val KotlinCompilation<*>.sourceFiles: List<File> + get() = kotlinSourceSets.flatMap { it.sourceFiles } - private fun getDependentSourceSet(compilation: KotlinCompilation<*>?) = compilation - ?.let { it.allKotlinSourceSets - it.kotlinSourceSets }.orEmpty() + private val KotlinSourceSet.sourceFiles: List<File> + get() = kotlin.sourceDirectories.filter { it.exists() }.toList() - private fun getDependentSourceSetRoots(compilation: KotlinCompilation<*>?): List<File> = - getDependentSourceSet(compilation)?.flatMap { it.kotlin.sourceDirectories } - .filter { it.exists() } + private val KotlinCompilation<*>.dependentSourceSets: Set<KotlinSourceSet> + get() = (allKotlinSourceSets - kotlinSourceSets) - private fun getClasspath(compilation: KotlinCompilation<*>?): List<File> = compilation - ?.compileDependencyFiles - ?.files - ?.toList() - ?.filter { it.exists() } - .orEmpty() + private val KotlinCompilation<*>.classpath: List<File> + get() = if (target.isAndroidTarget()) { + getClasspathFromAndroidTask(this) + } else { + getClasspathFromRegularTask(this) + } // This is a workaround for KT-33893 private fun getClasspathFromAndroidTask(compilation: KotlinCompilation<*>): List<File> = (compilation .compileKotlinTask as? KotlinCompile) - ?.classpath?.files?.toList() ?: getClasspath(compilation) - - private fun getMainCompilation(target: KotlinTarget) = - getCompilation(target, getMainCompilationName(target)) - - private fun getCompilation(target: KotlinTarget, name: String) = - target.compilations.getByName(name) - - private fun getMainCompilationName(target: KotlinTarget) = if (target.isAndroidTarget()) - getVariants(project).filter { it.buildType.name == BuilderConstants.RELEASE }.map { it.name }.first() - else - KotlinCompilation.MAIN_COMPILATION_NAME - - private fun getVariants(project: Project): Set<BaseVariant> { - val androidExtension = project.extensions.getByName("android") - val baseVariants = when (androidExtension) { - is AppExtension -> androidExtension.applicationVariants.toSet() - is LibraryExtension -> { - androidExtension.libraryVariants.toSet() + - if (androidExtension is FeatureExtension) { - androidExtension.featureVariants.toSet() - } else { - emptySet<BaseVariant>() - } - } - is TestExtension -> androidExtension.applicationVariants.toSet() - else -> emptySet() - } - val testVariants = if (androidExtension is TestedExtension) { - androidExtension.testVariants.toSet() + androidExtension.unitTestVariants.toSet() - } else { - emptySet<BaseVariant>() - } - - return baseVariants + testVariants - } + ?.classpath?.files?.toList() ?: getClasspathFromRegularTask(compilation) - private fun getPlatformName(platform: KotlinPlatformType): String = - if (platform == KotlinPlatformType.androidJvm) KotlinPlatformType.jvm.toString() else platform.toString() + private fun getClasspathFromRegularTask(compilation: KotlinCompilation<*>): List<File> = + compilation + .compileDependencyFiles + .files + .toList() + .filter { it.exists() } data class PlatformData( val name: String?, val classpath: List<File>, val sourceRoots: List<File>, - val dependentSourceRoots: List<File>, val dependentSourceSets: List<String>, val platform: String ) : Serializable diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt index f4fa7aaa..8c4e0c4c 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt @@ -20,7 +20,7 @@ open class DokkaCollectorTask : DefaultTask() { @TaskAction fun collect() { - val passesConfigurations = getProjects(project).filter { it.name in modules }.map { + val passesConfigurations = getProjects(project).filter { it.name in modules }.mapNotNull { val task = try { it.tasks.getByName(DOKKA_TASK_NAME, DokkaTask::class) } catch (e: UnknownTaskException) { @@ -33,12 +33,11 @@ open class DokkaCollectorTask : DefaultTask() { outputDir = outputDirectory cacheRoot = passesConfigurations.first().cacheRoot format = passesConfigurations.first().format - generateIndexPages = passesConfigurations.first().generateIndexPages } configuration = passesConfigurations.fold(initial) { acc, it: GradleDokkaConfigurationImpl -> - if(acc.format != it.format || acc.generateIndexPages != it.generateIndexPages || acc.cacheRoot != it.cacheRoot) - throw IllegalStateException("Dokka task configurations differ on core arguments (format, generateIndexPages, cacheRoot)") + if(acc.format != it.format || acc.cacheRoot != it.cacheRoot) + throw IllegalStateException("Dokka task configurations differ on core arguments (format, cacheRoot)") acc.passesConfigurations = acc.passesConfigurations + it.passesConfigurations acc.pluginsClasspath = (acc.pluginsClasspath + it.pluginsClasspath).distinct() acc diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt index a1bfdb96..2ef85de2 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt @@ -35,9 +35,9 @@ open class DokkaMultimoduleTask : DefaultTask(), Configurable { System.setProperty(DokkaTask.COLORS_ENABLED_PROPERTY, "false") try { - loadFatJar() + loadCore() val bootstrapClass = - ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaMultimoduleBootstrapImpl") + ClassloaderContainer.coreClassLoader!!.loadClass("org.jetbrains.dokka.DokkaMultimoduleBootstrapImpl") val bootstrapInstance = bootstrapClass.constructors.first().newInstance() val bootstrapProxy: DokkaBootstrap = automagicTypedProxy( javaClass.classLoader, @@ -85,10 +85,10 @@ open class DokkaMultimoduleTask : DefaultTask(), Configurable { } } - private fun loadFatJar() { - if (ClassloaderContainer.fatJarClassLoader == null) { + private fun loadCore() { + if (ClassloaderContainer.coreClassLoader == null) { val jars = dokkaRuntime!!.resolve() - ClassloaderContainer.fatJarClassLoader = URLClassLoader( + ClassloaderContainer.coreClassLoader = URLClassLoader( jars.map { it.toURI().toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader().parent ) diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt index 2de95493..5a420d4d 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt @@ -15,15 +15,16 @@ import org.jetbrains.dokka.ReflectDsl import org.jetbrains.dokka.ReflectDsl.isNotInstance import org.jetbrains.dokka.gradle.ConfigurationExtractor.PlatformData import org.jetbrains.dokka.plugability.Configurable -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import java.io.File import java.net.URLClassLoader import java.util.concurrent.Callable import java.util.function.BiConsumer +import kotlin.system.exitProcess open class DokkaTask : DefaultTask(), Configurable { private val ANDROID_REFERENCE_URL = Builder("https://developer.android.com/reference/").build() private val GLOBAL_CONFIGURATION_NAME = "global" // Used for copying perPackageOptions to other platforms + private val configExtractor = ConfigurationExtractor(project) @Suppress("MemberVisibilityCanBePrivate") fun defaultKotlinTasks(): List<Task> = with(ReflectDsl) { @@ -57,8 +58,6 @@ open class DokkaTask : DefaultTask(), Configurable { var subProjects: List<String> = emptyList() @Input - var impliedPlatforms: MutableList<String> = arrayListOf() - override val pluginsConfiguration: Map<String, String> = mutableMapOf() @Optional @@ -66,54 +65,47 @@ open class DokkaTask : DefaultTask(), Configurable { var cacheRoot: String? = null @Classpath - lateinit var pluginsConfig: Configuration + lateinit var pluginsClasspathConfiguration: Configuration var dokkaSourceSets: NamedDomainObjectContainer<GradlePassConfigurationImpl> @Suppress("UNCHECKED_CAST") @Nested get() = (DslObject(this).extensions.getByName(SOURCE_SETS_EXTENSION_NAME) as NamedDomainObjectContainer<GradlePassConfigurationImpl>) internal set(value) = DslObject(this).extensions.add(SOURCE_SETS_EXTENSION_NAME, value) - var configuration: GradlePassConfigurationImpl - @Suppress("UNCHECKED_CAST") - @Nested get() = DslObject(this).extensions.getByType(GradlePassConfigurationImpl::class.java) - internal set(value) = DslObject(this).extensions.add(CONFIGURATION_EXTENSION_NAME, value) - - var config: GradleDokkaConfigurationImpl? = null - - // Configure Dokka with closure in Gradle Kotlin DSL - fun configuration(action: Action<in GradlePassConfigurationImpl>) = action.execute(configuration) - private val kotlinTasks: List<Task> by lazy { - extractKotlinCompileTasks( - configuration.collectKotlinTasks ?: { defaultKotlinTasks() }) + extractKotlinCompileTasks({ + dokkaSourceSets.map { + it.collectKotlinTasks?.invoke() + } + }.takeIf { it().isNotEmpty() } ?: { defaultKotlinTasks() } + ) } - private val configExtractor = ConfigurationExtractor(project) - @Input var disableAutoconfiguration: Boolean = false + @Input + var offlineMode: Boolean = false + private var outputDiagnosticInfo: Boolean = false // Workaround for Gradle, which fires some methods (like collectConfigurations()) multiple times in its lifecycle - private fun loadFatJar() { - if (ClassloaderContainer.fatJarClassLoader == null) { + private fun loadCore() { + if (ClassloaderContainer.coreClassLoader == null) { val jars = dokkaRuntime!!.resolve() - ClassloaderContainer.fatJarClassLoader = URLClassLoader( + ClassloaderContainer.coreClassLoader = URLClassLoader( jars.map { it.toURI().toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader().parent ) } } - private fun extractKotlinCompileTasks(collectTasks: () -> List<Any?>?): List<Task> { + protected fun extractKotlinCompileTasks(collectTasks: () -> List<Any?>?): List<Task> { val inputList = (collectTasks.invoke() ?: emptyList()).filterNotNull() val (paths, other) = inputList.partition { it is String } - val taskContainer = project.tasks - val tasksByPath = paths.map { - taskContainer.findByPath(it as String) ?: throw IllegalArgumentException("Task with path '$it' not found") + project.tasks.findByPath(it as String) ?: throw IllegalArgumentException("Task with path '$it' not found") } other @@ -134,7 +126,7 @@ open class DokkaTask : DefaultTask(), Configurable { private fun Iterable<String>.toProjects(): List<Project> = project.subprojects.toList().filter { this.contains(it.name) } - private fun collectSuppressedFiles(sourceRoots: List<SourceRoot>) = + protected open fun collectSuppressedFiles(sourceRoots: List<SourceRoot>) = if (project.isAndroidProject()) { val generatedRoot = project.buildDir.resolve("generated").absoluteFile sourceRoots @@ -147,25 +139,21 @@ open class DokkaTask : DefaultTask(), Configurable { } @TaskAction - fun generate() { - generateForConfig(config ?: getConfiguration()) - } + fun generate() = getConfiguration()?.let { generate(it) } ?: exitProcess(0) - internal fun generateForConfig(configuration: GradleDokkaConfigurationImpl) { + protected open fun generate(configuration: GradleDokkaConfigurationImpl) { outputDiagnosticInfo = true val kotlinColorsEnabledBefore = System.getProperty(COLORS_ENABLED_PROPERTY) ?: "false" System.setProperty(COLORS_ENABLED_PROPERTY, "false") try { - loadFatJar() + loadCore() val bootstrapClass = - ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl") + ClassloaderContainer.coreClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl") val bootstrapInstance = bootstrapClass.constructors.first().newInstance() val bootstrapProxy: DokkaBootstrap = automagicTypedProxy(javaClass.classLoader, bootstrapInstance) - val gson = GsonBuilder().setPrettyPrinting().create() - bootstrapProxy.configure( BiConsumer { level, message -> when (level) { @@ -176,7 +164,7 @@ open class DokkaTask : DefaultTask(), Configurable { "error" -> logger.error(message) } }, - gson.toJson(configuration) + GsonBuilder().setPrettyPrinting().create().toJson(configuration) ) bootstrapProxy.generate() @@ -186,68 +174,78 @@ open class DokkaTask : DefaultTask(), Configurable { } } - internal fun getConfiguration(): GradleDokkaConfigurationImpl { + internal open fun getConfiguration(): GradleDokkaConfigurationImpl? { val globalConfig = dokkaSourceSets.toList().find { it.name.toLowerCase() == GLOBAL_CONFIGURATION_NAME } - val defaultModulesConfiguration = collectConfigurations() - .map { defaultPassConfiguration(it, globalConfig) } + val defaultModulesConfiguration = passConfigurations + .map { defaultPassConfiguration(it, globalConfig) }.takeIf { it.isNotEmpty() } + ?: listOf( + defaultPassConfiguration( + collectSinglePassConfiguration(GradlePassConfigurationImpl("main")), + null + ) + ).takeIf { project.isNotMultiplatformProject() } ?: emptyList() + + if (defaultModulesConfiguration.isEmpty()) { + logger.error("No source sets to document found, exiting") + return null + } + return GradleDokkaConfigurationImpl().apply { outputDir = project.file(outputDirectory).absolutePath format = outputFormat - generateIndexPages = true - cacheRoot = cacheRoot - impliedPlatforms = impliedPlatforms + cacheRoot = this@DokkaTask.cacheRoot + offlineMode = this@DokkaTask.offlineMode passesConfigurations = defaultModulesConfiguration - pluginsClasspath = pluginsConfig.resolve().toList() + pluginsClasspath = pluginsClasspathConfiguration.resolve().toList() pluginsConfiguration = this@DokkaTask.pluginsConfiguration } } - private fun collectConfigurations() = - if (this.dokkaSourceSets.isNotEmpty()) collectMultipassConfiguration() else listOf(collectSinglePassConfiguration(configuration)) - private fun collectMultipassConfiguration() = dokkaSourceSets - .filterNot { it.name.toLowerCase() == GLOBAL_CONFIGURATION_NAME } - .map { collectSinglePassConfiguration(it) } + protected val passConfigurations: List<GradlePassConfigurationImpl> + get() = dokkaSourceSets + .filterNot { it.name.toLowerCase() == GLOBAL_CONFIGURATION_NAME } + .map { collectSinglePassConfiguration(it) } - private fun collectSinglePassConfiguration(config: GradlePassConfigurationImpl): GradlePassConfigurationImpl { + protected fun collectSinglePassConfiguration(config: GradlePassConfigurationImpl): GradlePassConfigurationImpl { val userConfig = config - /*.let { - if (it.collectKotlinTasks != null) { - configExtractor.extractFromKotlinTasks(extractKotlinCompileTasks(it.collectKotlinTasks!!)) - ?.let { platformData -> mergeUserConfigurationAndPlatformData(it, platformData) } ?: it - } else { - it + .apply { + collectKotlinTasks?.let { + configExtractor.extractFromKotlinTasks(extractKotlinCompileTasks(it)) + .fold(this) { config, platformData -> + mergeUserConfigurationAndPlatformData(config, platformData) + } + } } - }*/ if (disableAutoconfiguration) return userConfig - val baseConfig = configExtractor.extractConfiguration(userConfig.name, userConfig.androidVariant) + val baseConfig = configExtractor.extractConfiguration(userConfig.name) ?.let { mergeUserConfigurationAndPlatformData(userConfig, it) } ?: if (this.dokkaSourceSets.isNotEmpty()) { if (outputDiagnosticInfo) logger.warn( - "Could not find target with name: ${userConfig.name} in Kotlin Gradle Plugin, " + - "using only user provided configuration for this target" + "Could not find source set with name: ${userConfig.name} in Kotlin Gradle Plugin, " + + "using only user provided configuration for this source set" ) userConfig } else { - logger.warn("Could not find target with name: ${userConfig.name} in Kotlin Gradle Plugin") - collectFromSinglePlatformOldPlugin(userConfig.name) + if (outputDiagnosticInfo) + logger.warn("Could not find source set with name: ${userConfig.name} in Kotlin Gradle Plugin") + collectFromSinglePlatformOldPlugin(userConfig.name, userConfig) } return if (subProjects.isNotEmpty()) { try { - subProjects.toProjects().fold(baseConfig) { config, subProject -> + subProjects.toProjects().fold(baseConfig) { configAcc, subProject -> mergeUserConfigurationAndPlatformData( - config, - ConfigurationExtractor(subProject).extractConfiguration(config.name, config.androidVariant)!! + configAcc, + ConfigurationExtractor(subProject).extractConfiguration(userConfig.name)!! ) } } catch (e: NullPointerException) { logger.warn( - "Cannot extract sources from subProjects. Do you have the Kotlin plugin in version 1.3.30+ " + - "and the Kotlin plugin applied in the root project?" + "Cannot extract sources from subProjects. Do you have the Kotlin plugin applied in the root project?" ) baseConfig } @@ -256,49 +254,52 @@ open class DokkaTask : DefaultTask(), Configurable { } } - private fun collectFromSinglePlatformOldPlugin(name: String) = - configExtractor.extractFromKotlinTasks(name, kotlinTasks) - ?.let { mergeUserConfigurationAndPlatformData(configuration, it) } + protected fun collectFromSinglePlatformOldPlugin(name: String, userConfig: GradlePassConfigurationImpl) = + kotlinTasks.find { it.name == name } + ?.let { configExtractor.extractFromKotlinTasks(listOf(it)) } + ?.singleOrNull() + ?.let { mergeUserConfigurationAndPlatformData(userConfig, it) } ?: configExtractor.extractFromJavaPlugin() - ?.let { mergeUserConfigurationAndPlatformData(configuration, it) } - ?: configuration + ?.let { mergeUserConfigurationAndPlatformData(userConfig, it) } + ?: userConfig - private fun mergeUserConfigurationAndPlatformData( + protected fun mergeUserConfigurationAndPlatformData( userConfig: GradlePassConfigurationImpl, autoConfig: PlatformData ) = userConfig.copy().apply { - sourceSetName = autoConfig.name ?: "" + sourceSetID = autoConfig.name ?: "" sourceRoots.addAll(userConfig.sourceRoots.union(autoConfig.sourceRoots.toSourceRoots()).distinct()) - dependentSourceRoots.addAll(userConfig.dependentSourceRoots.union(autoConfig.dependentSourceRoots.toSourceRoots()).distinct()) dependentSourceSets.addAll(userConfig.dependentSourceSets.union(autoConfig.dependentSourceSets).distinct()) classpath = userConfig.classpath.union(autoConfig.classpath.map { it.absolutePath }).distinct() if (userConfig.platform == null && autoConfig.platform != "") platform = autoConfig.platform } - private fun defaultPassConfiguration( + protected fun defaultPassConfiguration( config: GradlePassConfigurationImpl, globalConfig: GradlePassConfigurationImpl? ): GradlePassConfigurationImpl { - if (config.moduleName == "") { + if (config.moduleName.isBlank()) { config.moduleName = project.name } - if (config.sourceSetName.isEmpty()) { - config.sourceSetName = config.name.substringBeforeLast("Main").takeIf(String::isNotBlank) ?: config.platform.toString() + if (config.sourceSetID.isBlank()) { + config.sourceSetID = config.name.takeIf(String::isNotBlank) ?: config.analysisPlatform.key } - config.classpath = (config.classpath as List<Any>).map { it.toString() }.distinct() // Workaround for Groovy's GStringImpl + config.displayName = config.sourceSetID.substringBeforeLast("Main") + config.classpath = + (config.classpath as List<Any>).map { it.toString() }.distinct() // Workaround for Groovy's GStringImpl config.sourceRoots = config.sourceRoots.distinct().toMutableList() config.samples = config.samples.map { project.file(it).absolutePath } config.includes = config.includes.map { project.file(it).absolutePath } config.suppressedFiles += collectSuppressedFiles(config.sourceRoots) - if (project.isAndroidProject() && !config.noAndroidSdkLink) { // TODO: introduce Android as a separate Dokka platform? + if (project.isAndroidProject() && !config.noAndroidSdkLink) { config.externalDocumentationLinks.add(ANDROID_REFERENCE_URL) } - if (config.platform != null && config.platform.toString().isNotBlank()) { + if (config.platform?.isNotBlank() == true) { config.analysisPlatform = dokkaPlatformFromString(config.platform.toString()) } - if (globalConfig != null) { + globalConfig?.let { config.perPackageOptions.addAll(globalConfig.perPackageOptions) config.externalDocumentationLinks.addAll(globalConfig.externalDocumentationLinks) config.sourceLinks.addAll(globalConfig.sourceLinks) @@ -309,7 +310,7 @@ open class DokkaTask : DefaultTask(), Configurable { } private fun dokkaPlatformFromString(platform: String) = when (platform.toLowerCase()) { - KotlinPlatformType.androidJvm.toString().toLowerCase(), "androidjvm", "android" -> Platform.jvm + "androidjvm", "android" -> Platform.jvm "metadata" -> Platform.common else -> Platform.fromString(platform) } @@ -321,7 +322,7 @@ open class DokkaTask : DefaultTask(), Configurable { // Needed for Gradle incremental build @InputFiles fun getInputFiles(): FileCollection { - val config = collectConfigurations() + val config = passConfigurations return project.files(config.flatMap { it.sourceRoots }.map { project.fileTree(File(it.path)) }) + project.files(config.flatMap { it.includes }) + project.files(config.flatMap { it.samples }.map { project.fileTree(File(it)) }) @@ -329,7 +330,7 @@ open class DokkaTask : DefaultTask(), Configurable { @Classpath fun getInputClasspath(): FileCollection = - project.files((collectConfigurations().flatMap { it.classpath } as List<Any>).map { project.fileTree(File(it.toString())) }) + project.files((passConfigurations.flatMap { it.classpath } as List<Any>).map { project.fileTree(File(it.toString())) }) companion object { const val COLORS_ENABLED_PROPERTY = "kotlin.colors.enabled" diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt index 7fdadd41..2787bb4e 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt @@ -27,9 +27,9 @@ class GradleSourceRootImpl: SourceRoot, Serializable { open class GradlePassConfigurationImpl(@Transient val name: String = ""): PassConfiguration { @Input @Optional override var classpath: List<String> = emptyList() @Input override var moduleName: String = "" - @Input override var sourceSetName: String = "" + @Input override var displayName: String = "" + @Input override var sourceSetID: String = "" @Input override var sourceRoots: MutableList<SourceRoot> = mutableListOf() - @Input override var dependentSourceRoots: MutableList<SourceRoot> = mutableListOf() @Input override var dependentSourceSets: MutableList<String> = mutableListOf() @Input override var samples: List<String> = emptyList() @Input override var includes: List<String> = emptyList() @@ -48,13 +48,9 @@ open class GradlePassConfigurationImpl(@Transient val name: String = ""): PassCo @Input override var noJdkLink: Boolean = false @Input var noAndroidSdkLink: Boolean = false @Input override var suppressedFiles: List<String> = emptyList() - @Input override var collectInheritedExtensionsFromLibraries: Boolean = false @Input override var analysisPlatform: Platform = Platform.DEFAULT @Input @Optional var platform: String? = null - @Input override var targets: List<String> = emptyList() - @Input @Optional override var sinceKotlin: String? = null @Transient var collectKotlinTasks: (() -> List<Any?>?)? = null - @Input @Optional @Transient var androidVariant: String? = null fun kotlinTasks(taskSupplier: Callable<List<Any>>) { collectKotlinTasks = { taskSupplier.call() } @@ -129,9 +125,8 @@ class GradleDokkaModuleDescription: DokkaModuleDescription { class GradleDokkaConfigurationImpl: DokkaConfiguration { override var outputDir: String = "" override var format: String = "html" - override var generateIndexPages: Boolean = false override var cacheRoot: String? = null - override var impliedPlatforms: List<String> = emptyList() + override var offlineMode: Boolean = false override var passesConfigurations: List<GradlePassConfigurationImpl> = emptyList() override var pluginsClasspath: List<File> = emptyList() override var pluginsConfiguration: Map<String, String> = mutableMapOf() diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt index 1049656e..d2a0f043 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt @@ -8,23 +8,31 @@ import java.io.File import java.io.InputStream import java.util.* -internal const val CONFIGURATION_EXTENSION_NAME = "configuration" internal const val SOURCE_SETS_EXTENSION_NAME = "dokkaSourceSets" internal const val DOKKA_TASK_NAME = "dokka" internal const val DOKKA_COLLECTOR_TASK_NAME = "dokkaCollector" internal const val DOKKA_MULTIMODULE_TASK_NAME = "dokkaMultimodule" open class DokkaPlugin : Plugin<Project> { - override fun apply(project: Project) { loadDokkaVersion() val dokkaRuntimeConfiguration = addConfiguration(project) val pluginsConfiguration = project.configurations.create("dokkaPlugins").apply { dependencies.add(project.dependencies.create("org.jetbrains.dokka:dokka-base:${DokkaVersion.version}")) + attributes.attribute( + org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, + project.objects.named(org.gradle.api.attributes.Usage::class.java, "java-runtime") + ) + isCanBeConsumed = false } addDokkaTasks(project, dokkaRuntimeConfiguration, pluginsConfiguration, DokkaTask::class.java) addDokkaCollectorTasks(project, DokkaCollectorTask::class.java) - addDokkaMultimoduleTasks(project.rootProject, dokkaRuntimeConfiguration, pluginsConfiguration, DokkaMultimoduleTask::class.java) + addDokkaMultimoduleTasks( + project.rootProject, + dokkaRuntimeConfiguration, + pluginsConfiguration, + DokkaMultimoduleTask::class.java + ) } private fun loadDokkaVersion() = @@ -32,7 +40,9 @@ open class DokkaPlugin : Plugin<Project> { private fun addConfiguration(project: Project) = project.configurations.create("dokkaRuntime").apply { - defaultDependencies { dependencies -> dependencies.add(project.dependencies.create("org.jetbrains.dokka:dokka-core:${DokkaVersion.version}")) } + defaultDependencies { dependencies -> + dependencies.add(project.dependencies.create("org.jetbrains.dokka:dokka-core:${DokkaVersion.version}")) + } } private fun addDokkaTasks( @@ -48,9 +58,8 @@ open class DokkaPlugin : Plugin<Project> { } project.tasks.withType(taskClass) { task -> task.dokkaSourceSets = project.container(GradlePassConfigurationImpl::class.java) - task.configuration = GradlePassConfigurationImpl() task.dokkaRuntime = runtimeConfiguration - task.pluginsConfig = pluginsConfiguration + task.pluginsClasspathConfiguration = pluginsConfiguration task.outputDirectory = File(project.rootProject.buildDir, "$DOKKA_TASK_NAME/${project.name}").absolutePath } } @@ -65,7 +74,6 @@ open class DokkaPlugin : Plugin<Project> { project.tasks.create(DOKKA_COLLECTOR_TASK_NAME, taskClass) } project.tasks.withType(taskClass) { task -> - task.modules = emptyList() task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath } } @@ -103,5 +111,5 @@ object DokkaVersion { object ClassloaderContainer { @JvmField - var fatJarClassLoader: ClassLoader? = null + var coreClassLoader: ClassLoader? = null }
\ No newline at end of file diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt index 3369a640..a4bf65ee 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt @@ -7,7 +7,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -fun Project.isAndroidProject() = try { +internal fun Project.isAndroidProject() = try { project.extensions.getByName("android") true } catch(e: UnknownDomainObjectException) { @@ -16,4 +16,17 @@ fun Project.isAndroidProject() = try { false } -fun KotlinTarget.isAndroidTarget() = this.platformType == KotlinPlatformType.androidJvm
\ No newline at end of file +internal fun Project.isNotMultiplatformProject() = !isMultiplatformProject() + +internal fun Project.isMultiplatformProject() = try { + project.extensions.getByType(KotlinMultiplatformExtension::class.java) + true +} catch(e: UnknownDomainObjectException) { + false +} catch (e: NoClassDefFoundError){ + false +} catch(e: ClassNotFoundException) { + false +} + +internal fun KotlinTarget.isAndroidTarget() = this.platformType == KotlinPlatformType.androidJvm
\ No newline at end of file |