From 5ec19c2417489cb4964bcb017a8ffe7a559cdbb9 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Wed, 4 Aug 2021 18:32:17 +0300 Subject: [PATCH] [Gradle, JS] Up-to-date checks for Node js and yarn ^KT-47845 fixed --- .../gradle/internal/ProcessedFilesCache.kt | 12 +------- .../targets/js/nodejs/NodeJsSetupTask.kt | 22 ++++++++++++++ .../kotlin/gradle/targets/js/utils.kt | 29 +++++++++++++++++++ .../gradle/targets/js/yarn/YarnSetupTask.kt | 22 ++++++++++++++ 4 files changed, 74 insertions(+), 11 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt index fc263f5fa36..94b4b02a20a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt @@ -10,6 +10,7 @@ import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonWriter import org.gradle.internal.hash.FileHasher +import org.jetbrains.kotlin.gradle.targets.js.toHex import java.io.File /** @@ -92,17 +93,6 @@ internal open class ProcessedFilesCache( endObject() } - fun ByteArray.toHex(): String { - val result = CharArray(size * 2) { ' ' } - var i = 0 - forEach { - val n = it.toInt() - result[i++] = Character.forDigit(n shr 4 and 0xF, 16) - result[i++] = Character.forDigit(n and 0xF, 16) - } - return String(result) - } - private fun decodeHexString(hexString: String): ByteArray { check(hexString.length % 2 == 0) val bytes = ByteArray(hexString.length / 2) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt index 16860096b4e..d821f679085 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt @@ -7,6 +7,7 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.jetbrains.kotlin.gradle.logging.kotlinInfo import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService +import org.jetbrains.kotlin.gradle.targets.js.calculateDirHash import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics import java.io.File @@ -36,6 +37,9 @@ abstract class NodeJsSetupTask : DefaultTask() { val destination: File @OutputDirectory get() = env.nodeDir + val destinationHashFile: File + @OutputFile get() = destination.parentFile.resolve("${destination.name}.hash") + @Transient @get:Internal internal lateinit var configuration: Provider @@ -78,11 +82,29 @@ abstract class NodeJsSetupTask : DefaultTask() { fun exec() { logger.kotlinInfo("Using node distribution from '$nodeJsDist'") + val upToDate = destinationHashFile.let { file -> + if (file.exists()) { + file.useLines { + it.single() == calculateDirHash(destination) + } + } else false + } + + if (upToDate) return + + if (destination.isDirectory) { + destination.deleteRecursively() + } + unpackNodeArchive(nodeJsDist, destination.parentFile) // parent because archive contains name already if (!env.isWindows) { File(env.nodeExecutable).setExecutable(true) } + + destinationHashFile.writeText( + calculateDirHash(destination)!! + ) } private fun unpackNodeArchive(archive: File, destination: File) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt index cc7becdaa00..9f9bab24865 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js import org.jetbrains.kotlin.gradle.utils.appendLine import java.io.File +import java.security.MessageDigest fun Appendable.appendConfigsFromDir(confDir: File) { val files = confDir.listFiles() ?: return @@ -23,6 +24,34 @@ fun Appendable.appendConfigsFromDir(confDir: File) { } } +fun ByteArray.toHex(): String { + val result = CharArray(size * 2) { ' ' } + var i = 0 + forEach { + val n = it.toInt() + result[i++] = Character.forDigit(n shr 4 and 0xF, 16) + result[i++] = Character.forDigit(n and 0xF, 16) + } + return String(result) +} + +fun calculateDirHash(dir: File): String? { + if (!dir.isDirectory) return null + val md = MessageDigest.getInstance("MD5") + dir.walk() + .forEach { file -> + md.update(file.absolutePath.toByteArray()) + if (file.isFile) { + file.inputStream().use { + md.update(it.readBytes()) + } + } + } + + val digest = md.digest() + + return digest.toHex() +} const val JS = "js" const val JS_MAP = "js.map" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSetupTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSetupTask.kt index 6ee7f4f7708..478f973b9b0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSetupTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSetupTask.kt @@ -12,6 +12,7 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.jetbrains.kotlin.gradle.logging.kotlinInfo import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService +import org.jetbrains.kotlin.gradle.targets.js.calculateDirHash import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics @@ -41,6 +42,9 @@ open class YarnSetupTask : DefaultTask() { val destination: File @OutputDirectory get() = env.home + val destinationHashFile: File + @OutputFile get() = destination.parentFile.resolve("${destination.name}.hash") + init { group = NodeJsRootPlugin.TASKS_GROUP_NAME description = "Download and install a local yarn version" @@ -89,7 +93,25 @@ open class YarnSetupTask : DefaultTask() { fun setup() { logger.kotlinInfo("Using yarn distribution from '$yarnDist'") + val upToDate = destinationHashFile.let { file -> + if (file.exists()) { + file.useLines { + it.single() == calculateDirHash(destination) + } + } else false + } + + if (upToDate) return + + if (destination.isDirectory) { + destination.deleteRecursively() + } + extract(yarnDist, destination.parentFile) // parent because archive contains name already + + destinationHashFile.writeText( + calculateDirHash(destination)!! + ) } private fun extract(archive: File, destination: File) {