@@ -8,21 +8,27 @@ import java.io.FileNotFoundException
88import java.io.IOException
99import java.io.OutputStream
1010import java.nio.file.Path
11+ import java.nio.file.attribute.FileTime
1112import java.util.zip.ZipEntry
1213import java.util.zip.ZipOutputStream
14+ import kotlin.io.path.absolute
1315import kotlin.io.path.isDirectory
1416import kotlin.io.path.listDirectoryEntries
1517import kotlin.io.path.name
1618
1719internal fun OutputStream.createZipFile (contents : Path ) =
1820 ZipOutputStream (this ).use { zipOutputStream ->
19- contents.listDirectoryEntries().forEach { file ->
20- if (file.isDirectory()) {
21- zipDirectory(file.toFile(), file.name, zipOutputStream)
22- } else {
23- zipFile(file.toFile(), zipOutputStream)
21+ contents.listDirectoryEntries()
22+ // Sorting to add ZIP entries in deterministic order, to provide exactly the same ZIP regardless of
23+ // generation time.
24+ .sortedBy { it.absolute().toString() }
25+ .forEach { file ->
26+ if (file.isDirectory()) {
27+ zipDirectory(file.toFile(), file.name, zipOutputStream)
28+ } else {
29+ zipFile(file.toFile(), zipOutputStream)
30+ }
2431 }
25- }
2632 zipOutputStream.flush()
2733 }
2834
@@ -45,7 +51,15 @@ private fun zipDirectory(
4551 zipDirectory(file, parentFolder + " /" + file.getName(), zos)
4652 continue
4753 }
48- zos.putNextEntry(ZipEntry (parentFolder + " /" + file.getName()))
54+ val zipEntry =
55+ ZipEntry (parentFolder + " /" + file.getName()).apply {
56+ // Resetting various timestamps to provide exactly the same ZIP regardless of generation time.
57+ time = 0
58+ creationTime = FileTime .fromMillis(0 )
59+ lastModifiedTime = FileTime .fromMillis(0 )
60+ lastAccessTime = FileTime .fromMillis(0 )
61+ }
62+ zos.putNextEntry(zipEntry)
4963 val bis =
5064 BufferedInputStream (
5165 FileInputStream (file),
@@ -73,7 +87,15 @@ private fun zipFile(
7387 file : File ,
7488 zos : ZipOutputStream ,
7589) {
76- zos.putNextEntry(ZipEntry (file.getName()))
90+ val zipEntry =
91+ ZipEntry (file.getName()).apply {
92+ // Resetting various timestamps to provide exactly the same ZIP regardless of generation time.
93+ time = 0
94+ creationTime = FileTime .fromMillis(0 )
95+ lastModifiedTime = FileTime .fromMillis(0 )
96+ lastAccessTime = FileTime .fromMillis(0 )
97+ }
98+ zos.putNextEntry(zipEntry)
7799 val bis =
78100 BufferedInputStream (
79101 FileInputStream (
0 commit comments