diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizationCache.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt similarity index 77% rename from libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizationCache.kt rename to libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt index 9bc5f7a75d1..732eab90e7f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizationCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt @@ -12,37 +12,35 @@ import org.jetbrains.kotlin.commonizer.* import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.resolveCommonizedDirectory import java.io.File import java.io.FileOutputStream +import java.io.ObjectInputStream +import java.io.Serializable import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock -internal class NativeDistributionCommonizationCache( +class NativeDistributionCommonizerCache( + private val outputDirectory: File, + private val konanHome: File, private val logger: Logger, - private val isCachingEnabled: Boolean, - private val commonizer: NativeDistributionCommonizer -) : NativeDistributionCommonizer { - + private val isCachingEnabled: Boolean +) : Serializable { fun isUpToDate( - konanHome: File, outputDirectory: File, outputTargets: Set - ): Boolean = lock.withLock(outputDirectory) { - todoTargets(konanHome, outputDirectory, outputTargets) + outputTargets: Set + ): Boolean = lock.withLock { + todoTargets(outputTargets) }.isEmpty() - override fun commonizeNativeDistribution( - konanHome: File, - outputDirectory: File, + /** + * Calls [writeCacheAction] for uncached targets and marks them as cached if it succeeds + */ + fun writeCacheForUncachedTargets( outputTargets: Set, - logLevel: CommonizerLogLevel, - additionalSettings: List>, - ): Unit = lock.withLock(outputDirectory) { - val todoOutputTargets = todoTargets(konanHome, outputDirectory, outputTargets) + writeCacheAction: (todoTargets: Set) -> Unit + ) = lock.withLock { + val todoOutputTargets = todoTargets(outputTargets) if (todoOutputTargets.isEmpty()) return@withLock - /* Invoke commonizer with only 'to do' targets */ - commonizer.commonizeNativeDistribution( - konanHome, outputDirectory, todoOutputTargets, logLevel, additionalSettings - ) + writeCacheAction(todoOutputTargets) - /* Mark targets as successfully commonized */ todoOutputTargets .map { outputTarget -> resolveCommonizedDirectory(outputDirectory, outputTarget) } .filter { commonizedDirectory -> commonizedDirectory.isDirectory } @@ -50,14 +48,14 @@ internal class NativeDistributionCommonizationCache( } private fun todoTargets( - konanHome: File, outputDirectory: File, outputTargets: Set + outputTargets: Set ): Set { lock.checkLocked(outputDirectory) logInfo("Calculating cache state for $outputTargets") if (!isCachingEnabled) { logInfo("Cache disabled") - return if (isMissingPlatformLibraries(konanHome, outputTargets)) return emptySet() + return if (isMissingPlatformLibraries(outputTargets)) return emptySet() else outputTargets } @@ -68,7 +66,7 @@ internal class NativeDistributionCommonizationCache( val todoOutputTargets = outputTargets - cachedOutputTargets - if (todoOutputTargets.isEmpty() || isMissingPlatformLibraries(konanHome, todoOutputTargets)) { + if (todoOutputTargets.isEmpty() || isMissingPlatformLibraries(todoOutputTargets)) { logInfo("All available targets are commonized already - Nothing to do") if (todoOutputTargets.isNotEmpty()) { logInfo("Platforms cannot be commonized, because of missing platform libraries: $todoOutputTargets") @@ -80,13 +78,8 @@ internal class NativeDistributionCommonizationCache( return todoOutputTargets } - private fun isCached(directory: File): Boolean { - val successMarkerFile = directory.resolve(".success") - return successMarkerFile.isFile - } - private fun isMissingPlatformLibraries( - konanHome: File, missingOutputTargets: Set + missingOutputTargets: Set ): Boolean { // If all platform lib dirs are missing, we can also return fast from the cache without invoking // the commonizer @@ -96,15 +89,26 @@ internal class NativeDistributionCommonizationCache( .none { platformLibsDir -> platformLibsDir.exists() } } + private fun isCached(directory: File): Boolean { + val successMarkerFile = directory.resolve(".success") + return successMarkerFile.isFile + } + /** * Re-entrant lock implementation capable of locking a given output directory * even between multiple process (Gradle Daemons) */ - private val lock = object { + @Transient + private var lock = Lock() + + private fun logInfo(message: String) = + logger.info("Native Distribution Commonization: $message") + + private inner class Lock { private val reentrantLock = ReentrantLock() private val lockedOutputDirectories = mutableSetOf() - fun withLock(outputDirectory: File, action: () -> T): T { + fun withLock(action: () -> T): T { /* Enter intra-process wide lock */ reentrantLock.withLock { if (outputDirectory in lockedOutputDirectories) { @@ -143,6 +147,8 @@ internal class NativeDistributionCommonizationCache( } } - private fun logInfo(message: String) = - logger.info("Native Distribution Commonization: $message") -} + private fun readObject(input: ObjectInputStream) { + input.defaultReadObject() + lock = Lock() + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerTask.kt index 8393c1180a7..aaf09b4cd3b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerTask.kt @@ -39,22 +39,25 @@ internal open class NativeDistributionCommonizerTask private val runnerSettings = KotlinNativeCommonizerToolRunner.Settings(project) - private val isCachingEnabled = project.kotlinPropertiesProvider.enableNativeDistributionCommonizationCache - private val logLevel = project.commonizerLogLevel private val additionalSettings = project.additionalCommonizerSettings - private val kotlinVersion by lazy { project.getKotlinPluginVersion() } - @get:Internal internal val rootOutputDirectory: File = project.file { - project.file(konanHome) + project.file(project.konanHome) .resolve(KONAN_DISTRIBUTION_KLIB_DIR) .resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR) .resolve(URLEncoder.encode(project.getKotlinPluginVersion(), Charsets.UTF_8.name())) } + private val commonizerCache = NativeDistributionCommonizerCache( + outputDirectory = rootOutputDirectory, + konanHome = konanHome, + logger = logger, + isCachingEnabled = project.kotlinPropertiesProvider.enableNativeDistributionCommonizationCache + ) + @TaskAction protected fun run() { val commonizerRunner = KotlinNativeCommonizerToolRunner( @@ -62,27 +65,20 @@ internal open class NativeDistributionCommonizerTask settings = runnerSettings ) - val commonizer = NativeDistributionCommonizationCache( - isCachingEnabled = isCachingEnabled, - logger = logger, - commonizer = GradleCliCommonizer(commonizerRunner) - ) - - commonizer.commonizeNativeDistribution( - konanHome = konanHome, - outputDirectory = rootOutputDirectory, - outputTargets = commonizerTargets, - logLevel = logLevel, - additionalSettings = additionalSettings, - ) + commonizerCache.writeCacheForUncachedTargets(commonizerTargets) { todoOutputTargets -> + val commonizer = GradleCliCommonizer(commonizerRunner) + /* Invoke commonizer with only 'to do' targets */ + commonizer.commonizeNativeDistribution( + konanHome, rootOutputDirectory, todoOutputTargets, logLevel, additionalSettings + ) + } } init { project.registerCommonizerClasspathConfigurationIfNecessary() - // TODO(alakotka): Support upToDate checks -// outputs.upToDateWhen { -// commonizer.isUpToDate(konanHome, rootOutputDirectory, commonizerTargets) -// } + outputs.upToDateWhen { + commonizerCache.isUpToDate(commonizerTargets) + } } }