diff --git a/build/jvm-rules/zip/src/zip.kt b/build/jvm-rules/zip/src/zip.kt index b974d6a4fd0f..dc3bf14f91c6 100644 --- a/build/jvm-rules/zip/src/zip.kt +++ b/build/jvm-rules/zip/src/zip.kt @@ -11,7 +11,7 @@ import java.nio.file.StandardCopyOption import java.nio.file.attribute.DosFileAttributeView import java.nio.file.attribute.PosixFileAttributeView import java.nio.file.attribute.PosixFilePermission -import java.util.ArrayDeque +import java.util.PriorityQueue import java.util.zip.Deflater enum class AddDirEntriesMode { @@ -187,22 +187,22 @@ class ZipArchiver(@JvmField val fileAdded: ((String, Path) -> Boolean)? = null) } inline fun archiveDir(startDir: Path, addFile: (file: Path) -> Unit, excludes: List? = null) { - val dirCandidates = ArrayDeque() - dirCandidates.add(startDir) - val tempList = ArrayList() + if (Files.notExists(startDir)) { + return // empty + } + + val priorityQueue = PriorityQueue() + priorityQueue.add(startDir) while (true) { - val dir = dirCandidates.pollFirst() ?: break - tempList.clear() - val dirStream = try { - Files.newDirectoryStream(dir) - } - catch (_: NoSuchFileException) { + val path = priorityQueue.poll() ?: break // preserve sorted order + if (!Files.isDirectory(path)) { + addFile(path) continue } - dirStream.use { + Files.newDirectoryStream(path).use { if (excludes == null) { - tempList.addAll(it) + priorityQueue.addAll(it) } else { l@ for (child in it) { @@ -212,20 +212,10 @@ inline fun archiveDir(startDir: Path, addFile: (file: Path) -> Unit, excludes: L continue@l } } - tempList.add(child) + priorityQueue.add(child) } } } - - tempList.sort() - for (file in tempList) { - if (Files.isDirectory(file)) { - dirCandidates.add(file) - } - else { - addFile(file) - } - } } } diff --git a/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/ZipTest.kt b/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/ZipTest.kt index d62c7a2bf746..d574f984bd1d 100644 --- a/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/ZipTest.kt +++ b/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/ZipTest.kt @@ -38,6 +38,7 @@ import java.util.zip.CRC32 import java.util.zip.Deflater import java.util.zip.ZipEntry import java.util.zip.ZipInputStream +import kotlin.io.path.createDirectories import kotlin.io.path.name import kotlin.random.Random @@ -643,6 +644,27 @@ class ZipTest { } } } + + @Test + fun `ensure entries are in sorted order`(@TempDir tempDir: Path) { + val dir = Files.createDirectories(tempDir.resolve("dir")) + Files.writeString(dir.resolve("1"), "1") + Files.writeString(dir.resolve("2").resolve("1").createDirectories().resolve("1"), "2.1.1") + Files.writeString(dir.resolve("3").createDirectories().resolve("1"), "3.1") + Files.writeString(dir.resolve("4"), "4") + + val archiveFile = tempDir.resolve("archive.zip") + zip(archiveFile, mapOf(dir to ""), addDirEntriesMode = AddDirEntriesMode.NONE) + + HashMapZipFile.load(archiveFile).use { zipFile -> + assertThat(zipFile.entries.map { it.name }).containsExactly( + "1", + "2/1/1", + "3/1", + "4", + ) + } + } } private fun createTestFileInDir(dir: Path): String {