Sreenivas
02/04/2025, 9:45 AMSreenivas
02/04/2025, 9:46 AMjar {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
//No luck
tasks.withType(JavaCompile) {
options.compilerArgs.addAll(["-Xlint:unchecked", "-g:source,lines"])
}
//No luck
tasks.withType(JavaCompile) {
options.compilerArgs.addAll(["-g:none"])
}
//Worked - but this removes all debuging information, which will be a problem in prod if any issue occurs..
Jendrik Johannes
02/04/2025, 10:00 AMJendrik Johannes
02/04/2025, 10:01 AMSreenivas
02/04/2025, 10:06 AMVampire
02/04/2025, 10:11 AMthat should really be the defaultFeel free to open a feature request. 🙂 But actually I disagree to enable features by default that loose information for the small use-case of byte-to-byte reproducible builds that only a very small subset of users are interested in. 🤷♂️
Sreenivas
02/04/2025, 10:23 AMdeepy
02/04/2025, 10:24 AMSreenivas
02/04/2025, 10:32 AMSreenivas
02/04/2025, 10:33 AMdeepy
02/04/2025, 10:34 AMsetReproducibleFileOrder
to sort this)Julien Plissonneau Duquène
02/04/2025, 10:37 AMdiffoscope
that was specifically designed for that kind of comparisons.Sreenivas
02/04/2025, 10:37 AMJulien Plissonneau Duquène
02/04/2025, 10:37 AMdeepy
02/04/2025, 10:37 AMVampire
02/04/2025, 10:38 AMVampire
02/04/2025, 10:39 AMSreenivas
02/04/2025, 10:39 AMVampire
02/04/2025, 10:40 AMSreenivas
02/04/2025, 10:41 AMSreenivas
02/04/2025, 11:50 AMtasks.withType(AbstractArchiveTask) {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
but not this:
jar {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
Vampire
02/04/2025, 12:14 PMjar
task output, but the output of a different task.Vampire
02/04/2025, 12:15 PMtasks.withType(...) { ... }
as this breaks task-configuration avoidance for all those tasksVampire
02/04/2025, 12:15 PMtasks.withType(...).configureEach { ... }
Vampire
02/04/2025, 12:16 PMSreenivas
02/05/2025, 6:16 AMimport java.security.MessageDigest
tasks.register("computeClassFileChecksums") {
group = "verification"
description = "Computes SHA1 checksum for all compiled .class files"
doLast {
def classesDir = file("${buildDir}/classes") // Adjust for your output path
if (!classesDir.exists()) {
println "No class files found. Ensure the project is compiled first."
return
}
def digest = MessageDigest.getInstance("SHA-1")
def classFiles = classesDir.listFilesRecursively().findAll { it.name.endsWith(".class") }.sort()
classFiles.each { classFile ->
def sha1sum = classFile.bytes.inject(digest.clone()) { d, b -> d.update(b); d }.digest().encodeHex().toString()
println "$sha1sum ${classFile.path}"
}
}
}
// Helper function for recursive file listing
File.metaClass.listFilesRecursively = { ->
delegate.isDirectory() ? delegate.listFiles().collect { it.listFilesRecursively() }.flatten() : [delegate]
}
So in gitlab build-log it simply shows respective checksums. Which is better approach? or any other valuable suggestions?Julien Plissonneau Duquène
02/05/2025, 8:35 AMVampire
02/05/2025, 10:17 AMSreenivas
02/05/2025, 10:23 AMVampire
02/05/2025, 10:38 AMval computeClassFileChecksums by tasks.registering {
group = "verification"
description = "Computes SHA1 checksum for all compiled .class files"
inputs
.files(sourceSets.main.map { it.output })
.withPropertyName("inputFiles")
.skipWhenEmpty()
doLast {
val digest = MessageDigest.getInstance("SHA-1")
sourceSets
.main
.get()
.output
.asFileTree
.matching { include("**/*.class") }
.sorted()
.forEach { file ->
val sha1sum = digest
.apply { reset() }
.digest(file.readBytes())
.let { it.joinToString("") { "%02x".format(it) } }
println("$sha1sum ${file.path}")
}
}
}