From dc0a1df8d443610f27f6d22b2b6088d5402532ef Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Wed, 23 Mar 2022 19:21:07 +0100 Subject: [PATCH] Restore "AbstractKotlinCompileTool class now also implements PatternFilterable" This reverts commit d5e5513dfd42d78fea287adde1c6385277720848. --- .../gradle/KaptIncrementalWithIsolatingApt.kt | 1 + .../kapt/Kapt3KotlinGradleSubplugin.kt | 4 +- .../internal/kapt/KaptGenerateStubsTask.kt | 82 +++--- .../kotlin/gradle/internal/kapt/KaptTask.kt | 16 +- .../plugin/mpp/KotlinMultiplatformPlugin.kt | 6 +- .../sources/DefaultLanguageSettingsBuilder.kt | 4 +- .../gradle/targets/js/KotlinJsDcePlugin.kt | 2 +- .../gradle/targets/js/ir/KotlinBrowserJsIr.kt | 7 +- .../gradle/targets/js/ir/KotlinJsIrLink.kt | 39 +-- .../gradle/targets/js/ir/KotlinJsIrTarget.kt | 6 +- .../targets/native/tasks/KotlinNativeTasks.kt | 45 ++-- .../gradle/tasks/KotlinCompileCommon.kt | 20 +- .../kotlin/gradle/tasks/KotlinJsDce.kt | 40 ++- .../kotlin/gradle/tasks/SourceRoots.kt | 109 -------- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 244 ++++++++++++------ .../kotlin/gradle/utils/fileUtils.kt | 26 ++ 16 files changed, 332 insertions(+), 319 deletions(-) delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt index fe111b75cb8..0ded560cf85 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt @@ -306,6 +306,7 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { build(":mylibrary:assembleDebug") { assertEquals( listOf( + "baseLibrary/build/tmp/kapt3/stubs/debug/error/NonExistentClass.java", "mylibrary/src/main/java/com/example/lib/ExampleParcel.java", "baseLibrary/src/main/java/com/example/lib2/basemodule/BaseClassParcel.java", ).map { projectPath.resolve(it).toRealPath().toString() }.toSet(), diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index b5cc857e1dc..1b86fb8f013 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.tasks.registerTask @@ -576,8 +577,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kotlinCompilation.output.classesDirs.from(kaptTaskProvider.map { it.classesDir }) kotlinCompilation.compileKotlinTaskProvider.configure { - it as SourceTask - it.source(sourcesOutputDir, kotlinSourcesOutputDir) + (it as AbstractKotlinCompileTool<*>).setSource(sourcesOutputDir, kotlinSourcesOutputDir) } if (javaCompile != null) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index abbe5bbda39..fc79e07fd25 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -16,9 +16,8 @@ package org.jetbrains.kotlin.gradle.internal -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.Directory -import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.* +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* @@ -29,8 +28,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.tasks.* -import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer -import org.jetbrains.kotlin.gradle.tasks.SourceRoots import org.jetbrains.kotlin.gradle.utils.isParentOf import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile @@ -39,10 +36,12 @@ import javax.inject.Inject @CacheableTask abstract class KaptGenerateStubsTask @Inject constructor( - workerExecutor: WorkerExecutor -): KotlinCompile( + workerExecutor: WorkerExecutor, + objectFactory: ObjectFactory +) : KotlinCompile( KotlinJvmOptionsImpl(), - workerExecutor + workerExecutor, + objectFactory ) { internal class Configurator( @@ -71,23 +70,10 @@ abstract class KaptGenerateStubsTask @Inject constructor( kotlinCompileTask.compilerArgumentsContributor } ) - task.jvmSourceRoots.set( - providerFactory.provider { - kotlinCompileTask.getSourceRoots().let { compileTaskSourceRoots -> - SourceRoots.ForJvm( - compileTaskSourceRoots.kotlinSourceFiles.filter { task.isSourceRootAllowed(it) }, - compileTaskSourceRoots.javaSourceRoots.filter { task.isSourceRootAllowed(it) } - ) - } - } - ) task.verbose.set(KaptTask.queryKaptVerboseProperty(task.project)) } } - @field:Transient - override val sourceRootsContainer = FilteringSourceRootsContainer(objects, { isSourceRootAllowed(it) }) - @get:OutputDirectory abstract val stubsDir: DirectoryProperty @@ -118,28 +104,45 @@ abstract class KaptGenerateStubsTask @Inject constructor( @get:Incremental abstract val additionalSources: ConfigurableFileCollection - override fun setSource(vararg source: Any) { - super.setSource(sourceRootsContainer.add(sources)) - } + private fun File.isSourceRootAllowed(): Boolean = + !destinationDirectory.get().asFile.isParentOf(this) && + !stubsDir.asFile.get().isParentOf(this) && + generatedSourcesDirs.none { it.isParentOf(this) } - override fun setSource(source: Any) { - super.setSource(sourceRootsContainer.set(sources)) - } + override fun skipCondition(): Boolean = sources.isEmpty && javaSources.isEmpty - // TODO: prevent querying destinationDirectory on configuration time - private fun isSourceRootAllowed(source: File): Boolean = - !destinationDirectory.get().asFile.isParentOf(source) && - !stubsDir.asFile.get().isParentOf(source) && - generatedSourcesDirs.none { it.isParentOf(source) } + // Task need to run even if there is no Kotlin sources, but only Java + @get:Incremental + @get:InputFiles + @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.RELATIVE) + override val sources: FileCollection = super.sources + .asFileTree + .matching { patternFilterable -> + patternFilterable.include { it.isDirectory || it.file.isSourceRootAllowed() } + } + + override val javaSources: FileCollection = super.javaSources + .asFileTree + .matching { patternFilterable -> + patternFilterable.include { it.isDirectory || it.file.isSourceRootAllowed() } + } @get:Internal internal abstract val compileKotlinArgumentsContributor: Property> - override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - compileKotlinArgumentsContributor.get().contributeArguments(args, compilerArgumentsConfigurationFlags( - defaultsOnly, - ignoreClasspathResolutionErrors - )) + override fun setupCompilerArgs( + args: K2JVMCompilerArguments, + defaultsOnly: Boolean, + ignoreClasspathResolutionErrors: Boolean + ) { + compileKotlinArgumentsContributor.get().contributeArguments( + args, + compilerArgumentsConfigurationFlags( + defaultsOnly, + ignoreClasspathResolutionErrors + ) + ) val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath) args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray() @@ -148,9 +151,4 @@ abstract class KaptGenerateStubsTask @Inject constructor( args.classpathAsList = this.classpath.filter { it.exists() }.toList() args.destinationAsFile = this.destinationDirectory.get().asFile } - - @get:Internal - internal abstract val jvmSourceRoots: Property - - override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots.get() } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index 83335ec2935..77afeff7217 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -1,10 +1,10 @@ package org.jetbrains.kotlin.gradle.internal +import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection -import org.gradle.api.internal.ConventionTask import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property @@ -31,20 +31,16 @@ import javax.inject.Inject @CacheableTask abstract class KaptTask @Inject constructor( objectFactory: ObjectFactory -) : ConventionTask(), +) : DefaultTask(), TaskWithLocalState, UsesKotlinJavaToolchain { open class Configurator(protected val kotlinCompileTask: KotlinCompile) : TaskConfigurator { override fun configure(task: T) { val objectFactory = task.project.objects - val providerFactory = task.project.providers task.compilerClasspath.from({ kotlinCompileTask.defaultCompilerClasspath }) task.classpath.from(kotlinCompileTask.classpath) - task.kotlinSourceRoots.value( - providerFactory.provider { kotlinCompileTask.sourceRootsContainer.sourceRoots } - ).disallowChanges() task.compiledSources.from( kotlinCompileTask.destinationDirectory, Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } } @@ -52,7 +48,10 @@ abstract class KaptTask @Inject constructor( task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges() task.localStateDirectories.from(Callable { task.incAptCache.orNull }).disallowChanges() task.source.from( - objectFactory.fileCollection().from(task.kotlinSourceRoots, task.stubsDir).asFileTree + objectFactory.fileCollection().from( + kotlinCompileTask.javaSources, + task.stubsDir + ).asFileTree .matching { it.include("**/*.java") } .filter { f -> task.isRootAllowed(f) } ).disallowChanges() @@ -153,9 +152,6 @@ abstract class KaptTask @Inject constructor( @get:Internal var useBuildCache: Boolean = false - @get:Internal - abstract val kotlinSourceRoots: ListProperty - /** Needed for the model builder. */ @get:Internal abstract val sourceSetName: Property diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 75f5bacb284..cf3e3e05b22 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -8,12 +8,10 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import groovy.lang.Closure import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.AttributeContainer import org.gradle.api.file.DuplicatesStrategy import org.gradle.api.internal.plugins.DslObject import org.gradle.api.plugins.JavaBasePlugin -import org.gradle.api.tasks.SourceTask import org.gradle.api.tasks.TaskProvider import org.gradle.jvm.tasks.Jar import org.gradle.util.ConfigureUtil @@ -26,7 +24,6 @@ import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.sourceSetFreeCompilerArgsPropertyName import org.jetbrains.kotlin.gradle.plugin.mpp.internal.handleHierarchicalStructureFlagsMigration -import org.jetbrains.kotlin.gradle.plugin.mpp.isMain import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.hasKpmModel import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.registerDefaultVariantFactories @@ -41,6 +38,7 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.registerKotlinArtifactsExtension +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.* @@ -187,7 +185,7 @@ class KotlinMultiplatformPlugin : Plugin { (sourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run { compilerPluginOptionsTask = lazy { val associatedCompilation = primaryCompilationsBySourceSet[sourceSet] ?: metadataCompilation - project.tasks.getByName(associatedCompilation.compileKotlinTaskName) as SourceTask + project.tasks.getByName(associatedCompilation.compileKotlinTaskName) as AbstractKotlinCompileTool<*> } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt index c56eac798e9..8114880d02f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin.sources import org.gradle.api.InvalidUserDataException import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider -import org.gradle.api.tasks.SourceTask import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersion @@ -16,6 +15,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile import org.jetbrains.kotlin.project.model.LanguageSettings import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics @@ -70,7 +70,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { /* A Kotlin task that is responsible for code analysis of the owner of this language settings builder. */ @Transient // not needed during Gradle Instant Execution - var compilerPluginOptionsTask: Lazy = lazyOf(null) + var compilerPluginOptionsTask: Lazy?> = lazyOf(null) val compilerPluginArguments: List? get() { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsDcePlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsDcePlugin.kt index 01a3dce42a5..39e54039b15 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsDcePlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsDcePlugin.kt @@ -78,7 +78,7 @@ class KotlinJsDcePlugin : Plugin { dceTask.configure { it.classpath.from(configuration) it.destinationDirectory.set(it.dceOptions.outputDirectory?.let { File(it) } ?: outputDir) - it.setSource((kotlinTask.get() as Kotlin2JsCompile).outputFileProperty) + it.setSource(kotlinTask.map { task -> (task as Kotlin2JsCompile).outputFileProperty }) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt index 86ab7a022f0..0c42283875c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt @@ -101,9 +101,10 @@ open class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : ), listOf(compilation) ) { task -> - val entryFileProvider = binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + val entryFileProvider = binary.linkSyncTask.flatMap { syncTask -> + binary.linkTask.map { + syncTask.destinationDir.resolve(it.outputFileProperty.get().name) + } } webpackMajorVersion.choose( diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index d078b824f23..24c0e0bfe0a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileCollection import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.* @@ -25,7 +26,6 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.gradle.utils.getValue -import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.toHexString import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics @@ -57,6 +57,18 @@ abstract class KotlinJsIrLink @Inject constructor( } } + init { + // Not check sources, only klib module + disallowSourceChanges() + } + + @get:Internal + override val sources: FileCollection = super.sources + + override fun skipCondition(): Boolean { + return !entryModule.get().asFile.exists() + } + @Transient @get:Internal internal lateinit var compilation: KotlinCompilationData<*> @@ -81,10 +93,6 @@ abstract class KotlinJsIrLink @Inject constructor( @Input lateinit var mode: KotlinJsBinaryMode - // Not check sources, only klib module - @get:Internal - abstract override val sources: ConfigurableFileCollection - private val buildDir = project.buildDir @get:SkipWhenEmpty @@ -93,23 +101,24 @@ abstract class KotlinJsIrLink @Inject constructor( @get:PathSensitive(PathSensitivity.RELATIVE) internal abstract val entryModule: DirectoryProperty - override val destinationDirectory: DirectoryProperty - get() = objectFactory.directoryProperty().apply { + @get:Internal + override val destinationDirectory: DirectoryProperty = objectFactory.directoryProperty() + + @get:OutputDirectory + val normalizedDestinationDirectory: DirectoryProperty = objectFactory + .directoryProperty() + .apply { set( - destinationDirectory.flatMap { dir -> - if (kotlinOptions.outputFile == null) { - objectFactory.property(dir) + destinationDirectory.map { dir -> + if (kotlinOptions.outputFile != null) { + projectLayout.dir(outputFileProperty.map { it.parentFile }).get() } else { - projectLayout.dir(outputFileProperty.map { it.parentFile }) + dir } } ) } - override fun skipCondition(): Boolean { - return !entryModule.get().asFile.exists() - } - @get:Internal val rootCacheDirectory by lazy { buildDir.resolve("klib/cache") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt index 183095f792f..1a81e460833 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt @@ -136,7 +136,11 @@ constructor( binary.linkSyncTaskName ) { task -> task.from( - project.layout.file(binary.linkTask.flatMap { it.destinationDirectory.map { it.asFile } }) + project.layout.file( + binary.linkTask.flatMap { linkTask -> + linkTask.normalizedDestinationDirectory.map { it.asFile } + } + ) ) task.from(project.tasks.named(compilation.processResourcesTaskName)) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 329e66dd37a..c5d865d9599 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -18,6 +18,7 @@ import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.file.FileTree +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments @@ -132,7 +133,10 @@ abstract class AbstractKotlinNativeCompile< T : KotlinCommonToolOptions, K : KotlinNativeCompilationData<*>, M : CommonToolArguments - > : AbstractKotlinCompileTool() { + > +@Inject constructor( + private val objectFactory: ObjectFactory +): AbstractKotlinCompileTool(objectFactory) { @get:Internal abstract val compilation: K @@ -149,9 +153,6 @@ abstract class AbstractKotlinNativeCompile< @get:Internal abstract val baseName: String - @get:Internal - protected val objects = project.objects - @get:Internal protected val konanTarget by project.provider { compilation.konanTarget @@ -162,7 +163,7 @@ abstract class AbstractKotlinNativeCompile< // Avoid resolving these dependencies during task graph construction when we can't build the target: if (konanTarget.enabledOnCurrentHost) compilation.compileDependencyFiles.filterOutPublishableInteropLibs(project) - else objects.fileCollection() + else objectFactory.fileCollection() } @get:Classpath @@ -172,7 +173,7 @@ abstract class AbstractKotlinNativeCompile< @Deprecated("For native tasks use 'libraries' instead", ReplaceWith("libraries")) override val classpath: ConfigurableFileCollection - get() = objects.fileCollection().from(libraries) + get() = objectFactory.fileCollection().from(libraries) @get:Input val target: String by project.provider { compilation.konanTarget.name } @@ -209,7 +210,7 @@ abstract class AbstractKotlinNativeCompile< @get:Internal open val outputFile: Provider - get() = destinationDirectory.map { + get() = destinationDirectory.flatMap { val prefix = outputKind.prefix(konanTarget) val suffix = outputKind.suffix(konanTarget) val filename = "$prefix${baseName}$suffix".let { @@ -222,7 +223,7 @@ abstract class AbstractKotlinNativeCompile< } } - it.file(filename).asFile + objectFactory.property(it.file(filename).asFile) } // endregion @@ -309,8 +310,9 @@ abstract class KotlinNativeCompile constructor( @Internal @Transient // can't be serialized for Gradle configuration cache - final override val compilation: KotlinNativeCompilationData<*> -) : AbstractKotlinNativeCompile, StubK2NativeCompilerArguments>(), + final override val compilation: KotlinNativeCompilationData<*>, + objectFactory: ObjectFactory +) : AbstractKotlinNativeCompile, StubK2NativeCompilerArguments>(objectFactory), KotlinCompile { @get:Input @@ -463,8 +465,9 @@ abstract class KotlinNativeLink @Inject constructor( @Internal - val binary: NativeBinary -) : AbstractKotlinNativeCompile() { + val binary: NativeBinary, + objectFactory: ObjectFactory +) : AbstractKotlinNativeCompile(objectFactory) { @get:Internal final override val compilation: KotlinNativeCompilation get() = binary.compilation @@ -474,17 +477,13 @@ constructor( // Frameworks actively uses symlinks. // Gradle build cache transforms symlinks into regular files https://guides.gradle.org/using-build-cache/#symbolic_links outputs.cacheIf { outputKind != FRAMEWORK } + + this.setSource(compilation.compileKotlinTask.outputFile) + includes.clear() // we need to include non '.kt' or '.kts' files + disallowSourceChanges() } - @Internal // Taken into account by getSources(). - val intermediateLibrary: Provider = project.provider { compilation.compileKotlinTask.outputFile.get() } - - override val sources: ConfigurableFileCollection = objects - .fileCollection() - .from(intermediateLibrary) - .apply { disallowChanges() } - - override val destinationDirectory: DirectoryProperty = objects.directoryProperty().apply { + override val destinationDirectory: DirectoryProperty = objectFactory.directoryProperty().apply { set(binary.outputDirectory) } @@ -553,7 +552,7 @@ constructor( if (it is AbstractNativeLibrary) { project.configurations.getByName(it.exportConfigurationName) } else { - objects.fileCollection() + objectFactory.fileCollection() } } } @@ -652,7 +651,7 @@ constructor( binaryOptions, isStaticFramework, exportLibraries.files.filterKlibsPassedToCompiler(), - listOf(intermediateLibrary.get()), + sources.asFileTree.files.toList(), externalDependenciesArgs + cacheArgs ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index 07afea53b22..8b7fe7c3feb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.gradle.tasks import org.gradle.api.Project import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.work.InputChanges @@ -46,8 +47,10 @@ import javax.inject.Inject @CacheableTask abstract class KotlinCompileCommon @Inject constructor( override val kotlinOptions: KotlinMultiplatformCommonOptions, - workerExecutor: WorkerExecutor -) : AbstractKotlinCompile(), KotlinCommonCompile { + workerExecutor: WorkerExecutor, + objectFactory: ObjectFactory +) : AbstractKotlinCompile(objectFactory), + KotlinCommonCompile { class Configurator(compilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator(compilation) { override fun configure(task: KotlinCompileCommon) { @@ -85,7 +88,7 @@ abstract class KotlinCompileCommon @Inject constructor( } override val compilerRunner: Provider = - objects.propertyWithConvention( + objectFactory.propertyWithConvention( gradleCompileTaskProvider.map { GradleCompilerRunnerWithWorkers( it, @@ -101,9 +104,6 @@ abstract class KotlinCompileCommon @Inject constructor( override fun createCompilerArgs(): K2MetadataCompilerArguments = K2MetadataCompilerArguments() - override fun getSourceRoots(): SourceRoots = - SourceRoots.KotlinOnly.create(sources, sourceFilesExtensions.get()) - override fun setupCompilerArgs(args: K2MetadataCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { args.apply { fillDefaultValues() } super.setupCompilerArgs(args, defaultsOnly = defaultsOnly, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors) @@ -132,14 +132,14 @@ abstract class KotlinCompileCommon @Inject constructor( @get:PathSensitive(PathSensitivity.RELATIVE) @get:IgnoreEmptyDirectories @get:InputFiles - internal val refinesMetadataPaths: ConfigurableFileCollection = objects.fileCollection() + internal val refinesMetadataPaths: ConfigurableFileCollection = objectFactory.fileCollection() @get:Internal - internal val expectActualLinker = objects.property(Boolean::class.java) + internal val expectActualLinker = objectFactory.property(Boolean::class.java) override fun callCompilerAsync( args: K2MetadataCompilerArguments, - sourceRoots: SourceRoots, + kotlinSources: Set, inputChanges: InputChanges, taskOutputsBackup: TaskOutputsBackup? ) { @@ -152,7 +152,7 @@ abstract class KotlinCompileCommon @Inject constructor( outputFiles = allOutputFiles() ) compilerRunner.runMetadataCompilerAsync( - sourceRoots.kotlinSourceFiles.files.toList(), + kotlinSources.toList(), commonSourceSet.files.toList(), args, environment diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt index 60fe655b2a4..009e7618c72 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt @@ -16,11 +16,12 @@ package org.jetbrains.kotlin.gradle.tasks -import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.TaskAction +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.FileCollection +import org.gradle.api.model.ObjectFactory +import org.gradle.api.tasks.* import org.gradle.work.ChangeType +import org.gradle.work.Incremental import org.gradle.work.InputChanges import org.jetbrains.kotlin.cli.common.arguments.DevModeOverwritingStrategies import org.jetbrains.kotlin.cli.common.arguments.K2JSDceArguments @@ -31,17 +32,21 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptionsImpl import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.utils.canonicalPathWithoutExtension +import org.jetbrains.kotlin.gradle.utils.fileExtensionCasePermutations import java.io.File +import javax.inject.Inject @CacheableTask -abstract class KotlinJsDce : AbstractKotlinCompileTool(), KotlinJsDce { +abstract class KotlinJsDce @Inject constructor( + objectFactory: ObjectFactory +) : AbstractKotlinCompileTool(objectFactory), + KotlinJsDce { init { cacheOnlyIfEnabledForKotlin() - } - @get:Internal - internal val objects = project.objects + include("js".fileExtensionCasePermutations().map { "**/*.$it" }) + } override fun createCompilerArgs(): K2JSDceArguments = K2JSDceArguments() @@ -70,9 +75,18 @@ abstract class KotlinJsDce : AbstractKotlinCompileTool(), Kotl @Input var jvmArgs = mutableListOf() - private val buildDir by lazy { - project.buildDir - } + // Source could be empty, while classpath not + @get:Incremental + @get:InputFiles + @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.RELATIVE) + override val sources: FileCollection = super.sources + + @get:Incremental + @get:InputFiles + abstract override val classpath: ConfigurableFileCollection + + private val buildDir = project.layout.buildDirectory private val isDevMode get() = dceOptions.devMode || "-dev-mode" in dceOptions.freeCompilerArgs @@ -95,7 +109,7 @@ abstract class KotlinJsDce : AbstractKotlinCompileTool(), Kotl } else { classpath.asFileTree.files } - // TODO: use PatternFilterable here! + val inputFiles = sources.asFileTree.files.plus(classpathFiles) .filter { !kotlinFilesOnly || isDceCandidate(it) } .map { it.path } @@ -120,7 +134,7 @@ abstract class KotlinJsDce : AbstractKotlinCompileTool(), Kotl K2JSDce::class.java.name, defaultCompilerClasspath, log, - buildDir, + buildDir.get().asFile, jvmArgs ) throwGradleExceptionIfError(exitCode, KotlinCompilerExecutionStrategy.OUT_OF_PROCESS) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt deleted file mode 100644 index 1c7d7076c02..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt +++ /dev/null @@ -1,109 +0,0 @@ -package org.jetbrains.kotlin.gradle.tasks - -import org.gradle.api.file.FileCollection -import org.gradle.api.file.FileTree -import org.gradle.api.file.SourceDirectorySet -import org.gradle.api.logging.Logger -import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.Provider -import org.jetbrains.kotlin.gradle.logging.kotlinDebug -import org.jetbrains.kotlin.gradle.utils.isJavaFile -import org.jetbrains.kotlin.gradle.utils.isKotlinFile -import org.jetbrains.kotlin.gradle.utils.isParentOf -import java.io.File -import java.util.concurrent.Callable - -internal sealed class SourceRoots(val kotlinSourceFiles: FileCollection) { - private companion object { - fun dumpPaths(files: Iterable): String = - "[${files.map { it.canonicalPath }.sorted().joinToString(prefix = "\n\t", separator = ",\n\t")}]" - } - - open fun log(taskName: String, logger: Logger) { - logger.kotlinDebug { "$taskName source roots: ${dumpPaths(kotlinSourceFiles.files)}" } - } - - class ForJvm constructor( - kotlinSourceFiles: FileCollection, - val javaSourceRoots: FileCollection - ) : SourceRoots(kotlinSourceFiles) { - - companion object { - fun create( - taskSource: FileCollection, - sourceRoots: FilteringSourceRootsContainer, - sourceFilesExtensions: List - ): ForJvm { - return ForJvm( - taskSource.filter { it.isKotlinFile(sourceFilesExtensions) }, - sourceRoots.sourceRoots.filterJavaRoots( - taskSource.filter { it.isJavaFile() } - ) - ) - } - - private fun FileCollection.filterJavaRoots( - sourceDirs: FileCollection - ): FileCollection = filter { sourceRoot -> - sourceDirs.asSequence().map { it.parentFile }.any { sourceRoot.isParentOf(it) } - } - } - - override fun log(taskName: String, logger: Logger) { - super.log(taskName, logger) - logger.kotlinDebug { "$taskName java source roots: ${dumpPaths(javaSourceRoots.files)}" } - } - } - - class KotlinOnly(kotlinSourceFiles: FileCollection) : SourceRoots(kotlinSourceFiles) { - companion object { - fun create( - taskSource: FileCollection, - sourceFilesExtensions: List - ) = KotlinOnly( - taskSource.filter { it.isKotlinFile(sourceFilesExtensions) } - ) - } - } -} - -internal class FilteringSourceRootsContainer( - private val objectFactory: ObjectFactory, - val filter: (File) -> Boolean = { true } -) { - private val sourceContainers: MutableList = mutableListOf() - - private fun getFilteredSourceRootsFrom(any: Any) = objectFactory.fileCollection().from(Callable { - val resultItems = mutableListOf() - fun getRootsFrom(item: Any?) { - when (item) { - is SourceDirectorySet -> resultItems.add(item.sourceDirectories) - is Callable<*> -> getRootsFrom(item.call()) - is Provider<*> -> if (item.isPresent) getRootsFrom(item.get()) - is FileCollection -> resultItems.add(item) - is Iterable<*> -> item.forEach { getRootsFrom(it) } - is Array<*> -> item.forEach { getRootsFrom(it) } - is Any /* not null */ -> resultItems.add(item) - } - } - getRootsFrom(any) - resultItems - }).filter(filter) - - val sourceRoots: FileCollection - get() = getFilteredSourceRootsFrom(sourceContainers) - - fun clear() { - sourceContainers.clear() - } - - fun set(source: Any): FileCollection { - clear() - return add(source) - } - - fun add(vararg sources: Any): FileCollection { - sourceContainers.addAll(sources.toList()) - return getFilteredSourceRootsFrom(sources) - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index f9d73cbc00b..1064f5e8ff3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.tasks +import groovy.lang.Closure import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project @@ -19,10 +20,12 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters +import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.util.PatternFilterable +import org.gradle.api.tasks.util.PatternSet import org.gradle.work.ChangeType import org.gradle.work.Incremental import org.gradle.work.InputChanges @@ -57,13 +60,10 @@ import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib import org.jetbrains.kotlin.gradle.utils.* -import org.jetbrains.kotlin.incremental.ChangedFiles -import org.jetbrains.kotlin.incremental.ClasspathChanges +import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.* import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.* -import org.jetbrains.kotlin.incremental.ClasspathSnapshotFiles -import org.jetbrains.kotlin.incremental.IncrementalCompilerRunner import org.jetbrains.kotlin.library.impl.isKotlinLibrary import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.utils.JsLibraryUtils @@ -77,24 +77,44 @@ const val USING_JVM_INCREMENTAL_COMPILATION_MESSAGE = "Using Kotlin/JVM incremen const val USING_JS_INCREMENTAL_COMPILATION_MESSAGE = "Using Kotlin/JS incremental compilation" const val USING_JS_IR_BACKEND_MESSAGE = "Using Kotlin/JS IR backend" -abstract class AbstractKotlinCompileTool - : DefaultTask(), - //PatternFilterable, +abstract class AbstractKotlinCompileTool @Inject constructor( + objectFactory: ObjectFactory +) : DefaultTask(), + PatternFilterable, CompilerArgumentAwareWithInput, TaskWithLocalState { + private val patternFilterable = PatternSet() + + init { + patternFilterable.include( + DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS.flatMap { ext -> ext.fileExtensionCasePermutations().map { "**/*.$it" } } + ) + } + + private val sourceFiles = objectFactory.fileCollection() + @get:InputFiles @get:SkipWhenEmpty @get:IgnoreEmptyDirectories @get:PathSensitive(PathSensitivity.RELATIVE) - abstract val sources: ConfigurableFileCollection + open val sources: FileCollection = objectFactory.fileCollection() + .from( + { sourceFiles.asFileTree.matching(patternFilterable) } + ) + + @Deprecated("Use PatternFilterable methods to configure sources") + @get:Input + val sourceFilesExtensions: ListProperty = objectFactory + .listProperty(String::class.java) + .convention(DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS) /** * Sets the source for this task. * The given source object is evaluated as per [org.gradle.api.Project.files]. */ open fun setSource(source: Any) { - sources.from(source) + sourceFiles.from(source) } /** @@ -102,7 +122,57 @@ abstract class AbstractKotlinCompileTool * The given source object is evaluated as per [org.gradle.api.Project.files]. */ open fun setSource(vararg source: Any) { - sources.from(source) + sourceFiles.from(source) + } + + fun disallowSourceChanges() { + sourceFiles.disallowChanges() + } + + @Internal + final override fun getIncludes(): MutableSet = patternFilterable.includes + + @Internal + final override fun getExcludes(): MutableSet = patternFilterable.excludes + + final override fun setIncludes(includes: Iterable): PatternFilterable = also { + patternFilterable.setIncludes(includes) + } + + final override fun setExcludes(excludes: Iterable): PatternFilterable = also { + patternFilterable.setExcludes(excludes) + } + + final override fun include(vararg includes: String?): PatternFilterable = also { + patternFilterable.include(*includes) + } + + final override fun include(includes: Iterable): PatternFilterable = also { + patternFilterable.include(includes) + } + + final override fun include(includeSpec: Spec): PatternFilterable = also { + patternFilterable.include(includeSpec) + } + + final override fun include(includeSpec: Closure<*>): PatternFilterable = also { + patternFilterable.include(includeSpec) + } + + final override fun exclude(vararg excludes: String?): PatternFilterable = also { + patternFilterable.exclude(*excludes) + } + + final override fun exclude(excludes: Iterable): PatternFilterable = also { + patternFilterable.exclude(excludes) + } + + final override fun exclude(excludeSpec: Spec): PatternFilterable = also { + patternFilterable.exclude(excludeSpec) + } + + final override fun exclude(excludeSpec: Closure<*>): PatternFilterable = also { + patternFilterable.exclude(excludeSpec) } @get:Classpath @@ -187,7 +257,9 @@ abstract class GradleCompileTaskProvider @Inject constructor( ) } -abstract class AbstractKotlinCompile : AbstractKotlinCompileTool(), +abstract class AbstractKotlinCompile @Inject constructor( + objectFactory: ObjectFactory +) : AbstractKotlinCompileTool(objectFactory), CompileUsingKotlinDaemonWithNormalization { open class Configurator>(protected val compilation: KotlinCompilationData<*>) : TaskConfigurator { @@ -238,16 +310,13 @@ abstract class AbstractKotlinCompile : AbstractKotl @get:Inject internal abstract val fileSystemOperations: FileSystemOperations - @get:Internal - protected val objects: ObjectFactory = project.objects - // avoid creating directory in getter: this can lead to failure in parallel build @get:OutputDirectory - internal val taskBuildCacheableOutputDirectory: DirectoryProperty = objects.directoryProperty() + internal val taskBuildCacheableOutputDirectory: DirectoryProperty = objectFactory.directoryProperty() // avoid creating directory in getter: this can lead to failure in parallel build @get:LocalState - internal val taskBuildLocalStateDirectory: DirectoryProperty = objects.directoryProperty() + internal val taskBuildLocalStateDirectory: DirectoryProperty = objectFactory.directoryProperty() @get:Internal internal val buildHistoryFile @@ -277,20 +346,18 @@ abstract class AbstractKotlinCompile : AbstractKotl internal fun reportingSettings() = buildMetricsReporterService.orNull?.parameters?.reportingSettings ?: ReportingSettings() @get:Input - internal val useModuleDetection: Property = objects.property(Boolean::class.java).value(false) + internal val useModuleDetection: Property = objectFactory.property(Boolean::class.java).value(false) @get:Internal protected val multiModuleICSettings: MultiModuleICSettings get() = MultiModuleICSettings(buildHistoryFile.get().asFile, useModuleDetection.get()) @get:Classpath - open val pluginClasspath: ConfigurableFileCollection = objects.fileCollection() + open val pluginClasspath: ConfigurableFileCollection = objectFactory.fileCollection() @get:Internal internal val pluginOptions = CompilerPluginOptions() - @get:Input - val sourceFilesExtensions: ListProperty = objects.listProperty(String::class.java).value(DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS) /** * Plugin Data provided by [KpmCompilerPlugin] @@ -302,52 +369,52 @@ abstract class AbstractKotlinCompile : AbstractKotl // Input is needed to force rebuild even if source files are not changed @get:Input - internal val coroutines: Property = objects.property(Coroutines::class.java) + internal val coroutines: Property = objectFactory.property(Coroutines::class.java) @get:Internal - internal val javaOutputDir: DirectoryProperty = objects.directoryProperty() + internal val javaOutputDir: DirectoryProperty = objectFactory.directoryProperty() @get:Internal - internal val sourceSetName: Property = objects.property(String::class.java) + internal val sourceSetName: Property = objectFactory.property(String::class.java) @get:InputFiles @get:IgnoreEmptyDirectories @get:Incremental @get:PathSensitive(PathSensitivity.RELATIVE) - internal val commonSourceSet: ConfigurableFileCollection = objects.fileCollection() + internal val commonSourceSet: ConfigurableFileCollection = objectFactory.fileCollection() @get:Input - internal val moduleName: Property = objects.property(String::class.java) + internal val moduleName: Property = objectFactory.property(String::class.java) @get:Internal val abiSnapshotFile get() = taskBuildCacheableOutputDirectory.file(IncrementalCompilerRunner.ABI_SNAPSHOT_FILE_NAME) @get:Input - val abiSnapshotRelativePath: Property = objects.property(String::class.java).value( + val abiSnapshotRelativePath: Property = objectFactory.property(String::class.java).value( //TODO update to support any jar changes "$name/${IncrementalCompilerRunner.ABI_SNAPSHOT_FILE_NAME}" ) @get:Internal - internal val friendSourceSets = objects.listProperty(String::class.java) + internal val friendSourceSets = objectFactory.listProperty(String::class.java) @get:Internal // takes part in the compiler arguments - val friendPaths: ConfigurableFileCollection = objects.fileCollection() + val friendPaths: ConfigurableFileCollection = objectFactory.fileCollection() private val kotlinLogger by lazy { GradleKotlinLogger(logger) } abstract override val kotlinDaemonJvmArguments: ListProperty @get:Internal - protected val gradleCompileTaskProvider: Provider = objects + protected val gradleCompileTaskProvider: Provider = objectFactory .property( - objects.newInstance(project.gradle, this, project) + objectFactory.newInstance(project.gradle, this, project) ) @get:Internal internal open val compilerRunner: Provider = - objects.propertyWithConvention( + objectFactory.propertyWithConvention( gradleCompileTaskProvider.map { GradleCompilerRunner( it, @@ -410,8 +477,7 @@ abstract class AbstractKotlinCompile : AbstractKotl buildMetricsReporterService.orNull?.also { it.addTask(path, this.javaClass, buildMetrics) } } - protected open fun skipCondition(): Boolean = - getSourceRoots().kotlinSourceFiles.isEmpty() + protected open fun skipCondition(): Boolean = sources.isEmpty private val projectDir = project.rootProject.projectDir @@ -427,8 +493,7 @@ abstract class AbstractKotlinCompile : AbstractKotl inputChanges: InputChanges, taskOutputsBackup: TaskOutputsBackup? ) { - val sourceRoots = getSourceRoots() - val allKotlinSources = sourceRoots.kotlinSourceFiles + val allKotlinSources = sources.asFileTree.files logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(projectDir)}" } @@ -438,13 +503,12 @@ abstract class AbstractKotlinCompile : AbstractKotl return } - sourceRoots.log(this.name, logger) val args = prepareCompilerArguments() taskBuildCacheableOutputDirectory.get().asFile.mkdirs() taskBuildLocalStateDirectory.get().asFile.mkdirs() callCompilerAsync( args, - sourceRoots, + allKotlinSources, inputChanges, taskOutputsBackup ) @@ -472,22 +536,19 @@ abstract class AbstractKotlinCompile : AbstractKotl } } - @Internal - internal abstract fun getSourceRoots(): SourceRoots - /** * Compiler might be executed asynchronously. Do not do anything requiring end of compilation after this function is called. * @see [GradleKotlinCompilerWork] */ internal abstract fun callCompilerAsync( args: T, - sourceRoots: SourceRoots, + kotlinSources: Set, inputChanges: InputChanges, taskOutputsBackup: TaskOutputsBackup? ) @get:Input - internal val multiPlatformEnabled: Property = objects.property(Boolean::class.java) + internal val multiPlatformEnabled: Property = objectFactory.property(Boolean::class.java) @get:Internal internal val abstractKotlinCompileArgumentsContributor by lazy { @@ -536,8 +597,9 @@ internal inline val T.thisTaskProvider: TaskProvider @CacheableTask abstract class KotlinCompile @Inject constructor( override val kotlinOptions: KotlinJvmOptions, - workerExecutor: WorkerExecutor -) : AbstractKotlinCompile(), + workerExecutor: WorkerExecutor, + private val objectFactory: ObjectFactory +) : AbstractKotlinCompile(objectFactory), KotlinJvmCompile, UsesKotlinJavaToolchain { @@ -635,16 +697,7 @@ abstract class KotlinCompile @Inject constructor( } @get:Internal - internal val parentKotlinOptionsImpl: Property = objects.property(KotlinJvmOptions::class.java) - - @get:Internal - @field:Transient - internal open val sourceRootsContainer = FilteringSourceRootsContainer(objects) - - private val jvmSourceRoots by project.provider { - // serialize in the task state for configuration caching; avoid building anew in task execution, as it may access the project model - SourceRoots.ForJvm.create(sources, sourceRootsContainer, sourceFilesExtensions.get()) - } + internal val parentKotlinOptionsImpl: Property = objectFactory.property(KotlinJvmOptions::class.java) /** A package prefix that is used for locating Java sources in a directory structure with non-full-depth packages. * @@ -691,23 +744,29 @@ abstract class KotlinCompile @Inject constructor( } override val incrementalProps: List - get() = listOf(sources, commonSourceSet, classpathSnapshotProperties.classpath, classpathSnapshotProperties.classpathSnapshot) + get() = listOf( + sources, + javaSources, + commonSourceSet, + classpathSnapshotProperties.classpath, + classpathSnapshotProperties.classpathSnapshot + ) // Exclude classpathSnapshotDir from TaskOutputsBackup (see TaskOutputsBackup's kdoc for more info). */ override val taskOutputsBackupExcludes: List get() = classpathSnapshotProperties.classpathSnapshotDir.orNull?.asFile?.let { listOf(it) } ?: emptyList() @get:Internal - internal val defaultKotlinJavaToolchain: Provider = objects + internal val defaultKotlinJavaToolchain: Provider = objectFactory .propertyWithNewInstance({ this }) final override val kotlinJavaToolchainProvider: Provider = defaultKotlinJavaToolchain.cast() @get:Internal - override val compilerRunner: Provider = objects.propertyWithConvention( + override val compilerRunner: Provider = objectFactory.propertyWithConvention( // From Gradle 6.6 better to replace flatMap with provider.zip() defaultKotlinJavaToolchain.flatMap { toolchain -> - objects.property(gradleCompileTaskProvider.map { + objectFactory.property(gradleCompileTaskProvider.map { GradleCompilerRunnerWithWorkers( it, toolchain.currentJvmJdkToolsJar.orNull, @@ -762,17 +821,13 @@ abstract class KotlinCompile @Inject constructor( KotlinJvmCompilerArgumentsContributor(KotlinJvmCompilerArgumentsProvider(this)) } - override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots - override fun callCompilerAsync( args: K2JVMCompilerArguments, - sourceRoots: SourceRoots, + kotlinSources: Set, inputChanges: InputChanges, taskOutputsBackup: TaskOutputsBackup? ) { - sourceRoots as SourceRoots.ForJvm - - validateKotlinAndJavaHasSameTargetCompatibility(args, sourceRoots) + validateKotlinAndJavaHasSameTargetCompatibility(args, kotlinSources) val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val outputItemCollector = OutputItemsCollectorImpl() @@ -791,7 +846,7 @@ abstract class KotlinCompile @Inject constructor( ) } else null - @Suppress("ConvertArgumentToSet") + @Suppress("ConvertArgumentToSet", "DEPRECATION") val environment = GradleCompilerEnvironment( defaultCompilerClasspath, messageCollector, outputItemCollector, // In the incremental compiler, outputFiles will be cleaned on rebuild. However, because classpathSnapshotDir is not included in @@ -803,10 +858,12 @@ abstract class KotlinCompile @Inject constructor( incrementalCompilationEnvironment = icEnv, kotlinScriptExtensions = sourceFilesExtensions.get().toTypedArray() ) + logger.info("Kotlin source files: ${kotlinSources.joinToString()}") + logger.info("Java source files: ${javaSources.files.joinToString()}") compilerRunner.runJvmCompilerAsync( - sourceRoots.kotlinSourceFiles.files.toList(), + kotlinSources.toList(), commonSourceSet.toList(), - sourceRoots.javaSourceRoots, + javaSources.files, // we need here only directories where Java sources are located javaPackagePrefix, args, environment, @@ -815,8 +872,12 @@ abstract class KotlinCompile @Inject constructor( ) } - private fun validateKotlinAndJavaHasSameTargetCompatibility(args: K2JVMCompilerArguments, sourceRoots: SourceRoots.ForJvm) { - val mixedSourcesArePresent = !associatedJavaCompileTaskSources.isEmpty && !sourceRoots.kotlinSourceFiles.isEmpty + private fun validateKotlinAndJavaHasSameTargetCompatibility( + args: K2JVMCompilerArguments, + kotlinSources: Set + ) { + val mixedSourcesArePresent = !associatedJavaCompileTaskSources.isEmpty && + kotlinSources.isNotEmpty() if (mixedSourcesArePresent) { associatedJavaCompileTaskTargetCompatibility.orNull?.let { targetCompatibility -> val normalizedJavaTarget = when (targetCompatibility) { @@ -854,7 +915,7 @@ abstract class KotlinCompile @Inject constructor( if (it is AbstractCompile && it !is JavaCompile && it !is AbstractKotlinCompile<*> && - javaOutputDir.get().asFile.isParentOf(it.destinationDir) + javaOutputDir.get().asFile.isParentOf(it.destinationDirectory.get().asFile) ) { illegalTaskOrNull = illegalTaskOrNull ?: it } @@ -863,7 +924,7 @@ abstract class KotlinCompile @Inject constructor( val illegalTask = illegalTaskOrNull!! logger.info( "Kotlin inter-project IC is disabled: " + - "unknown task '$illegalTask' destination dir ${illegalTask.destinationDir} " + + "unknown task '$illegalTask' destination dir ${illegalTask.destinationDirectory.get().asFile} " + "intersects with java destination dir $javaOutputDir" ) } @@ -871,15 +932,34 @@ abstract class KotlinCompile @Inject constructor( } } - // override setSource to track source directory sets and files (for generated android folders) + private val javaSourceFiles = objectFactory.fileCollection() + + private fun javaFilesPatternFilter(patternFilterable: PatternFilterable) { + patternFilterable.include( + "java".fileExtensionCasePermutations().map { "**/*.$it" } + ) + } + + @get:Incremental + @get:InputFiles + @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.RELATIVE) + open val javaSources: FileCollection = objectFactory.fileCollection() + .from( + javaSourceFiles + .asFileTree + .matching(::javaFilesPatternFilter) + ) + + // override setSource to track Java sources as well override fun setSource(source: Any) { - sourceRootsContainer.set(source) + javaSourceFiles.from(source) super.setSource(source) } - // override source to track source directory sets and files (for generated android folders) + // override source to track Java sources as well override fun setSource(vararg source: Any) { - sourceRootsContainer.add(*source) + javaSourceFiles.from(*source) super.setSource(*source) } @@ -913,7 +993,8 @@ abstract class Kotlin2JsCompile @Inject constructor( override val kotlinOptions: KotlinJsOptions, objectFactory: ObjectFactory, workerExecutor: WorkerExecutor -) : AbstractKotlinCompile(), KotlinJsCompile { +) : AbstractKotlinCompile(objectFactory), + KotlinJsCompile { init { incremental = true @@ -997,7 +1078,7 @@ abstract class Kotlin2JsCompile @Inject constructor( abstract val optionalOutputFile: RegularFileProperty override val compilerRunner: Provider = - objects.propertyWithConvention( + objectFactory.propertyWithConvention( gradleCompileTaskProvider.map { GradleCompilerRunnerWithWorkers( it, @@ -1031,8 +1112,6 @@ abstract class Kotlin2JsCompile @Inject constructor( (kotlinOptions as KotlinJsOptionsImpl).updateArguments(args) } - override fun getSourceRoots() = SourceRoots.KotlinOnly.create(sources, sourceFilesExtensions.get()) - @get:InputFiles @get:IgnoreEmptyDirectories @get:Incremental @@ -1121,14 +1200,11 @@ abstract class Kotlin2JsCompile @Inject constructor( override fun callCompilerAsync( args: K2JSCompilerArguments, - sourceRoots: SourceRoots, + kotlinSources: Set, inputChanges: InputChanges, taskOutputsBackup: TaskOutputsBackup? ) { - sourceRoots as SourceRoots.KotlinOnly - logger.debug("Calling compiler") - //destinationDir.mkdirs() if (kotlinOptions.isIrBackendEnabled()) { logger.info(USING_JS_IR_BACKEND_MESSAGE) @@ -1174,7 +1250,7 @@ abstract class Kotlin2JsCompile @Inject constructor( ) processArgs(args) compilerRunner.runJsCompilerAsync( - sourceRoots.kotlinSourceFiles.files.toList(), + kotlinSources.toList(), commonSourceSet.toList(), args, environment, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt index 1fc7eb20448..5b043d2a0c4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt @@ -18,6 +18,32 @@ internal fun File.isJavaFile() = internal fun File.isKotlinFile(sourceFilesExtensions: List): Boolean = !isJavaFile() && sourceFilesExtensions.any { it.equals(extension, ignoreCase = true) } +/** + * Create all possible case-sensitive permutations for given [String]. + * + * Useful to create for [org.gradle.api.tasks.util.PatternFilterable] Ant-style patterns. + */ +@OptIn(ExperimentalStdlibApi::class) +internal fun String.fileExtensionCasePermutations(): List { + val lowercaseInput = lowercase() + val length = lowercaseInput.length + // number of permutations is 2^n + val max = 1 shl length + val result = mutableListOf() + var combination: CharArray + for (i in 0 until max) { + combination = lowercaseInput.toCharArray() + for (j in 0 until length) { + // If j-th bit is set, we convert it to upper case + if (((i shr j) and 1) == 1) { + combination[j] = combination[j].uppercaseChar() + } + } + result.add(String(combination)) + } + return result +} + internal fun File.relativeOrCanonical(base: File): String = relativeToOrNull(base)?.path ?: canonicalPath