Restore "AbstractKotlinCompileTool class now also implements PatternFilterable"

This reverts commit d5e5513dfd.
This commit is contained in:
Yahor Berdnikau
2022-03-23 19:21:07 +01:00
parent 4aa6d984fc
commit dc0a1df8d4
16 changed files with 332 additions and 319 deletions
@@ -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(),
@@ -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) {
@@ -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<CompilerArgumentsContributor<K2JVMCompilerArguments>>
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<SourceRoots.ForJvm>
override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots.get()
}
@@ -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<T: KaptTask>(protected val kotlinCompileTask: KotlinCompile) : TaskConfigurator<T> {
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<File>
/** Needed for the model builder. */
@get:Internal
abstract val sourceSetName: Property<String>
@@ -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<Project> {
(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<*>
}
}
}
@@ -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<SourceTask?> = lazyOf(null)
var compilerPluginOptionsTask: Lazy<AbstractKotlinCompileTool<*>?> = lazyOf(null)
val compilerPluginArguments: List<String>?
get() {
@@ -78,7 +78,7 @@ class KotlinJsDcePlugin : Plugin<Project> {
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 })
}
}
}
@@ -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(
@@ -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")
@@ -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))
@@ -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<M>() {
>
@Inject constructor(
private val objectFactory: ObjectFactory
): AbstractKotlinCompileTool<M>(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<File>
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<KotlinCommonOptions, KotlinNativeCompilationData<*>, StubK2NativeCompilerArguments>(),
final override val compilation: KotlinNativeCompilationData<*>,
objectFactory: ObjectFactory
) : AbstractKotlinNativeCompile<KotlinCommonOptions, KotlinNativeCompilationData<*>, StubK2NativeCompilerArguments>(objectFactory),
KotlinCompile<KotlinCommonOptions> {
@get:Input
@@ -463,8 +465,9 @@ abstract class KotlinNativeLink
@Inject
constructor(
@Internal
val binary: NativeBinary
) : AbstractKotlinNativeCompile<KotlinCommonToolOptions, KotlinNativeCompilation, StubK2NativeCompilerArguments>() {
val binary: NativeBinary,
objectFactory: ObjectFactory
) : AbstractKotlinNativeCompile<KotlinCommonToolOptions, KotlinNativeCompilation, StubK2NativeCompilerArguments>(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<File> = 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
)
@@ -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<K2MetadataCompilerArguments>(), KotlinCommonCompile {
workerExecutor: WorkerExecutor,
objectFactory: ObjectFactory
) : AbstractKotlinCompile<K2MetadataCompilerArguments>(objectFactory),
KotlinCommonCompile {
class Configurator(compilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator<KotlinCompileCommon>(compilation) {
override fun configure(task: KotlinCompileCommon) {
@@ -85,7 +88,7 @@ abstract class KotlinCompileCommon @Inject constructor(
}
override val compilerRunner: Provider<GradleCompilerRunner> =
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<File>,
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
@@ -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<K2JSDceArguments>(), KotlinJsDce {
abstract class KotlinJsDce @Inject constructor(
objectFactory: ObjectFactory
) : AbstractKotlinCompileTool<K2JSDceArguments>(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<K2JSDceArguments>(), Kotl
@Input
var jvmArgs = mutableListOf<String>()
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<K2JSDceArguments>(), 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<K2JSDceArguments>(), Kotl
K2JSDce::class.java.name,
defaultCompilerClasspath,
log,
buildDir,
buildDir.get().asFile,
jvmArgs
)
throwGradleExceptionIfError(exitCode, KotlinCompilerExecutionStrategy.OUT_OF_PROCESS)
@@ -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<File>): 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<String>
): 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<String>
) = KotlinOnly(
taskSource.filter { it.isKotlinFile(sourceFilesExtensions) }
)
}
}
}
internal class FilteringSourceRootsContainer(
private val objectFactory: ObjectFactory,
val filter: (File) -> Boolean = { true }
) {
private val sourceContainers: MutableList<Any> = mutableListOf()
private fun getFilteredSourceRootsFrom(any: Any) = objectFactory.fileCollection().from(Callable {
val resultItems = mutableListOf<Any>()
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)
}
}
@@ -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<T : CommonToolArguments>
: DefaultTask(),
//PatternFilterable,
abstract class AbstractKotlinCompileTool<T : CommonToolArguments> @Inject constructor(
objectFactory: ObjectFactory
) : DefaultTask(),
PatternFilterable,
CompilerArgumentAwareWithInput<T>,
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<String> = 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<T : CommonToolArguments>
* 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<String> = patternFilterable.includes
@Internal
final override fun getExcludes(): MutableSet<String> = patternFilterable.excludes
final override fun setIncludes(includes: Iterable<String>): PatternFilterable = also {
patternFilterable.setIncludes(includes)
}
final override fun setExcludes(excludes: Iterable<String>): PatternFilterable = also {
patternFilterable.setExcludes(excludes)
}
final override fun include(vararg includes: String?): PatternFilterable = also {
patternFilterable.include(*includes)
}
final override fun include(includes: Iterable<String>): PatternFilterable = also {
patternFilterable.include(includes)
}
final override fun include(includeSpec: Spec<FileTreeElement>): 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<String>): PatternFilterable = also {
patternFilterable.exclude(excludes)
}
final override fun exclude(excludeSpec: Spec<FileTreeElement>): 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<T : CommonCompilerArguments> : AbstractKotlinCompileTool<T>(),
abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constructor(
objectFactory: ObjectFactory
) : AbstractKotlinCompileTool<T>(objectFactory),
CompileUsingKotlinDaemonWithNormalization {
open class Configurator<T : AbstractKotlinCompile<*>>(protected val compilation: KotlinCompilationData<*>) : TaskConfigurator<T> {
@@ -238,16 +310,13 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : 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<T : CommonCompilerArguments> : AbstractKotl
internal fun reportingSettings() = buildMetricsReporterService.orNull?.parameters?.reportingSettings ?: ReportingSettings()
@get:Input
internal val useModuleDetection: Property<Boolean> = objects.property(Boolean::class.java).value(false)
internal val useModuleDetection: Property<Boolean> = 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<String> = objects.listProperty(String::class.java).value(DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS)
/**
* Plugin Data provided by [KpmCompilerPlugin]
@@ -302,52 +369,52 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
// Input is needed to force rebuild even if source files are not changed
@get:Input
internal val coroutines: Property<Coroutines> = objects.property(Coroutines::class.java)
internal val coroutines: Property<Coroutines> = 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<String> = objects.property(String::class.java)
internal val sourceSetName: Property<String> = 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<String> = objects.property(String::class.java)
internal val moduleName: Property<String> = objectFactory.property(String::class.java)
@get:Internal
val abiSnapshotFile
get() = taskBuildCacheableOutputDirectory.file(IncrementalCompilerRunner.ABI_SNAPSHOT_FILE_NAME)
@get:Input
val abiSnapshotRelativePath: Property<String> = objects.property(String::class.java).value(
val abiSnapshotRelativePath: Property<String> = 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<String>
@get:Internal
protected val gradleCompileTaskProvider: Provider<GradleCompileTaskProvider> = objects
protected val gradleCompileTaskProvider: Provider<GradleCompileTaskProvider> = objectFactory
.property(
objects.newInstance<GradleCompileTaskProvider>(project.gradle, this, project)
objectFactory.newInstance<GradleCompileTaskProvider>(project.gradle, this, project)
)
@get:Internal
internal open val compilerRunner: Provider<GradleCompilerRunner> =
objects.propertyWithConvention(
objectFactory.propertyWithConvention(
gradleCompileTaskProvider.map {
GradleCompilerRunner(
it,
@@ -410,8 +477,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : 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<T : CommonCompilerArguments> : 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<T : CommonCompilerArguments> : 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<T : CommonCompilerArguments> : 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<File>,
inputChanges: InputChanges,
taskOutputsBackup: TaskOutputsBackup?
)
@get:Input
internal val multiPlatformEnabled: Property<Boolean> = objects.property(Boolean::class.java)
internal val multiPlatformEnabled: Property<Boolean> = objectFactory.property(Boolean::class.java)
@get:Internal
internal val abstractKotlinCompileArgumentsContributor by lazy {
@@ -536,8 +597,9 @@ internal inline val <reified T : Task> T.thisTaskProvider: TaskProvider<out T>
@CacheableTask
abstract class KotlinCompile @Inject constructor(
override val kotlinOptions: KotlinJvmOptions,
workerExecutor: WorkerExecutor
) : AbstractKotlinCompile<K2JVMCompilerArguments>(),
workerExecutor: WorkerExecutor,
private val objectFactory: ObjectFactory
) : AbstractKotlinCompile<K2JVMCompilerArguments>(objectFactory),
KotlinJvmCompile,
UsesKotlinJavaToolchain {
@@ -635,16 +697,7 @@ abstract class KotlinCompile @Inject constructor(
}
@get:Internal
internal val parentKotlinOptionsImpl: Property<KotlinJvmOptions> = 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<KotlinJvmOptions> = 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<FileCollection>
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<File>
get() = classpathSnapshotProperties.classpathSnapshotDir.orNull?.asFile?.let { listOf(it) } ?: emptyList()
@get:Internal
internal val defaultKotlinJavaToolchain: Provider<DefaultKotlinJavaToolchain> = objects
internal val defaultKotlinJavaToolchain: Provider<DefaultKotlinJavaToolchain> = objectFactory
.propertyWithNewInstance({ this })
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchain> = defaultKotlinJavaToolchain.cast()
@get:Internal
override val compilerRunner: Provider<GradleCompilerRunner> = objects.propertyWithConvention(
override val compilerRunner: Provider<GradleCompilerRunner> = 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<File>,
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<File>
) {
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<K2JSCompilerArguments>(), KotlinJsCompile {
) : AbstractKotlinCompile<K2JSCompilerArguments>(objectFactory),
KotlinJsCompile {
init {
incremental = true
@@ -997,7 +1078,7 @@ abstract class Kotlin2JsCompile @Inject constructor(
abstract val optionalOutputFile: RegularFileProperty
override val compilerRunner: Provider<GradleCompilerRunner> =
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<File>,
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,
@@ -18,6 +18,32 @@ internal fun File.isJavaFile() =
internal fun File.isKotlinFile(sourceFilesExtensions: List<String>): 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<String> {
val lowercaseInput = lowercase()
val length = lowercaseInput.length
// number of permutations is 2^n
val max = 1 shl length
val result = mutableListOf<String>()
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