From caa01ebacfd03b5c0d7cdc582cd5f5326e4947e3 Mon Sep 17 00:00:00 2001 From: Brian Witt Date: Tue, 7 Jul 2026 20:04:17 -0700 Subject: [PATCH] ensure deterministic output Signed-off-by: Brian Witt --- .../icerock/gradle/generator/ResourceTypeGenerator.kt | 7 ++++++- .../icerock/gradle/metadata/resource/ResourceMetadata.kt | 4 ++-- .../gradle/tasks/GenerateMultiplatformResourcesTask.kt | 9 ++++++--- .../src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt | 3 +++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt index 4b50f1a09..d0ffd2bd3 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt @@ -14,6 +14,7 @@ import dev.icerock.gradle.metadata.container.ResourceType import dev.icerock.gradle.metadata.resource.ResourceMetadata import dev.icerock.gradle.utils.filterClass import org.gradle.api.tasks.util.PatternFilterable +import java.io.File import kotlin.reflect.KClass @Suppress("LongParameterList", "TooManyFunctions", "UnusedPrivateMember") @@ -28,7 +29,11 @@ internal class ResourceTypeGenerator( private val filter: PatternFilterable.() -> Unit, ) { fun generateMetadata(files: ResourcesFiles): List { - return generator.generateMetadata(files.matching(filter).ownSourceSet.fileTree.files) + // Sort for deterministic output; FileTree.files iteration is filesystem-dependent. + val sortedFiles: Set = files.matching(filter).ownSourceSet.fileTree.files + .sortedBy { it.absolutePath } + .toCollection(LinkedHashSet()) + return generator.generateMetadata(sortedFiles) } fun getImports(): List = platformResourceGenerator.imports() diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt index 06bf63e16..fdc59a890 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt @@ -61,7 +61,7 @@ internal data class StringMetadata( ) @Suppress("MagicNumber") - override fun contentHash(): String = values.hashCode().toString(16) + override fun contentHash(): String = values.toString().hashCode().toString(16) } @Serializable @@ -94,7 +94,7 @@ internal data class PluralMetadata( } @Suppress("MagicNumber") - override fun contentHash(): String = values.hashCode().toString(16) + override fun contentHash(): String = values.toString().hashCode().toString(16) } @Serializable diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt index edbdc11f5..7f5ff2b1a 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt @@ -155,9 +155,12 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { ) val serializer: KSerializer> = ListSerializer(ContainerMetadata.serializer()) - val inputMetadata: List = inputMetadataFiles.files.flatMap { file -> - json.decodeFromString(serializer, file.readText()) - } + // Sort for deterministic output. + val inputMetadata: List = inputMetadataFiles.files + .sortedBy { it.absolutePath } + .flatMap { file -> + json.decodeFromString(serializer, file.readText()) + } val outputMetadata: List = if (kotlinPlatformType.isCommon) { generator.generateCommonKotlin(files, inputMetadata) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt index 5df62d2a9..b0d2351dc 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt @@ -12,8 +12,11 @@ import java.io.InputStream import java.io.SequenceInputStream internal fun File.calculateResourcesHash(): String { + val root: File = this + // Sort for deterministic output; walkTopDown() order is filesystem-dependent. val inputStreams: List = walkTopDown() .filterNot { it.isDirectory } + .sortedBy { it.relativeTo(root).path } .map { it.inputStream() }.toList() val singleInputStream: InputStream = SequenceInputStream(inputStreams.toEnumeration())