[Gradle] Evaluate commonizedOutputLibraries in a changing provider

Add `changing` provider for Configuration Cache compatibility.
This makes AbstractCInteropCommonizerTask be compatible
with Configuration Cache.

^KT-49933
This commit is contained in:
Anton Lakotka
2023-01-16 14:16:56 +01:00
committed by Space Team
parent 15f2179557
commit 458e69f698
2 changed files with 46 additions and 2 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.base64Hash
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.ensureMaxFileNameLength
import org.jetbrains.kotlin.commonizer.identityString
import org.jetbrains.kotlin.gradle.utils.changing
import org.jetbrains.kotlin.gradle.utils.outputFilesProvider
import java.io.File
@@ -34,8 +35,10 @@ internal fun AbstractCInteropCommonizerTask.outputDirectory(group: CInteropCommo
internal fun AbstractCInteropCommonizerTask.commonizedOutputLibraries(dependent: CInteropCommonizerDependent): FileCollection {
return outputFilesProvider {
(commonizedOutputDirectory(dependent) ?: return@outputFilesProvider emptySet<File>())
.listFiles().orEmpty().toSet()
val outputDirectory = commonizedOutputDirectory(dependent) ?: return@outputFilesProvider emptySet<File>()
project.providers.changing {
outputDirectory.listFiles().orEmpty().toSet()
}
}
}
@@ -13,7 +13,10 @@ import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.provider.SetProperty
import org.gradle.api.provider.ValueSource
import org.gradle.api.provider.ValueSourceParameters
import java.io.File
import kotlin.reflect.KProperty
@@ -125,3 +128,41 @@ internal inline fun <reified T> Project.listProperty(noinline itemsProvider: ()
internal inline fun <reified T> Project.setProperty(noinline itemsProvider: () -> Iterable<T>): SetProperty<T> =
objects.setProperty(T::class.java).apply { set(provider(itemsProvider)) }
/**
* Changing Provider will be evaluated every time it accessed.
*
* And its producing [code] will be serilalised to Configuration Cache as is
* So that it still will be evaluated during Task Execution phase.
* It is very convenient for Configuration Cache compatibility.
*
* It is recommended to use Task Output's and map/flatMap them to other Task Inputs but in cases when TaskOutput's is not available
* as Gradle's Properties or Providers then this [changing] provider can be used.
*
* name `changing` and overall concept is borrowed from Gradle internal API [org.gradle.api.internal.provider.Providers.changing]
*
* @see org.gradle.api.internal.provider.ChangingProvider
*/
internal fun <T> ProviderFactory.changing(code: () -> T): Provider<T> {
@Suppress("UNCHECKED_CAST")
val adhocValueSourceClass = AdhocValueSource::class.java as Class<AdhocValueSource<T>>
return of(adhocValueSourceClass) { valueSourceSpec ->
valueSourceSpec.parameters {
it.producingLambda.set(code)
}
}
}
private abstract class AdhocValueSource<T> : ValueSource<T, AdhocValueSource.Parameters> {
// this interface can't be parameterized with T since it breaks internal Gradle logic
// This is why producingLambda is '() -> Any?' but not '() -> T'
interface Parameters : ValueSourceParameters {
val producingLambda: Property<() -> Any?>
}
override fun obtain(): T {
@Suppress("UNCHECKED_CAST")
return parameters.producingLambda.get().invoke() as T
}
}