Fix failures when a common source set compiled to nothing (KT-36674)

This could happen:
* when a common source set had no sources
* when the compile task of a common source set was disabled

In those cases, there were two subsequent failures:
* the metadata JAR could not interpret the missing klib file as ZIP
* the consumer could not read the empty klib in its dependencies

Issue #KT-36674 Fixed
This commit is contained in:
Sergey Igushkin
2020-03-03 19:08:58 +03:00
parent 066d413fb8
commit ad1a1ac49a
3 changed files with 38 additions and 21 deletions
@@ -30,11 +30,26 @@ class KlibBasedMppIT : BaseGradleIT() {
""".trimIndent()) """.trimIndent())
} }
@Test
fun testPublishingAndConsumptionWithEmptySourceSet() = testBuildWithDependency {
// KT-36674
projectDir.resolve("$dependencyModuleName/src/$hostSpecificSourceSet").run {
assertTrue { isDirectory }
deleteRecursively()
}
publishProjectDepAndAddDependency(validateHostSpecificPublication = false)
}
@Test @Test
fun testBuildWithPublishedDependency() = testBuildWithDependency { fun testBuildWithPublishedDependency() = testBuildWithDependency {
publishProjectDepAndAddDependency(validateHostSpecificPublication = true)
}
private fun Project.publishProjectDepAndAddDependency(validateHostSpecificPublication: Boolean) {
build(":$dependencyModuleName:publish") { build(":$dependencyModuleName:publish") {
assertSuccessful() assertSuccessful()
checkPublishedHostSpecificMetadata(this@build) if (validateHostSpecificPublication)
checkPublishedHostSpecificMetadata(this@build)
} }
gradleBuildScript().appendText("\n" + """ gradleBuildScript().appendText("\n" + """
@@ -371,30 +371,32 @@ private class JarArtifactMppDependencyMetadataExtractor(
artifactBySourceSet.forEach { (sourceSetName, artifact) -> artifactBySourceSet.forEach { (sourceSetName, artifact) ->
ZipFile(artifact).use { zip -> ZipFile(artifact).use { zip ->
val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") } val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList()
// TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR // TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR
// Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed // Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed
val extension =
projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension if (entries.any()) {
val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension
?: SourceSetMetadataLayout.METADATA.archiveExtension ?: SourceSetMetadataLayout.METADATA.archiveExtension
val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension")
resultFiles[sourceSetName] = project.files(extractToJarFile) val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension")
resultFiles[sourceSetName] = project.files(extractToJarFile)
if (doProcessFiles) { if (doProcessFiles) {
ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput -> ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput ->
for (entry in entries) { for (entry in entries) {
if (entry.isDirectory) if (entry.isDirectory)
continue continue
// Drop the source set name from the entry path // Drop the source set name from the entry path
val resultEntry = ZipEntry(entry.name.substringAfter("/")) val resultEntry = ZipEntry(entry.name.substringAfter("/"))
zip.getInputStream(entry).use { inputStream -> zip.getInputStream(entry).use { inputStream ->
resultZipOutput.putNextEntry(resultEntry) resultZipOutput.putNextEntry(resultEntry)
inputStream.copyTo(resultZipOutput) inputStream.copyTo(resultZipOutput)
resultZipOutput.closeEntry() resultZipOutput.closeEntry()
}
} }
} }
} }
@@ -532,9 +532,9 @@ internal fun getPublishedPlatformCompilations(project: Project): Map<KotlinUsage
internal fun Project.filesWithUnpackedArchives(from: FileCollection, extensions: Set<String>): FileCollection = internal fun Project.filesWithUnpackedArchives(from: FileCollection, extensions: Set<String>): FileCollection =
project.files(project.provider { project.files(project.provider {
from.map { from.mapNotNull {
if (it.extension in extensions) if (it.extension in extensions) {
project.zipTree(it) if (it.exists()) project.zipTree(it) else null
else it } else it
} }
}).builtBy(from) }).builtBy(from)