[Gradle] Changed the way of unpacking k/n dependencies

Creating `tar` process is not supported by configuration cache.
Inner Gradle copy and archive operations don't work well with symlinks.
That is why we are using utils from org.apache.commons:commons-compress.

^KT-66422 Fixed
This commit is contained in:
Dmitrii Krasnov
2024-03-07 20:10:49 +01:00
committed by Space Team
parent fb3c1f1a2f
commit f18d00e6f0
10 changed files with 231 additions and 47 deletions
@@ -19,9 +19,7 @@ package org.jetbrains.kotlin.konan.properties
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.Configurables
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.util.ArchiveType
import org.jetbrains.kotlin.konan.util.DependencyProcessor
import org.jetbrains.kotlin.konan.util.ProgressCallback
import org.jetbrains.kotlin.konan.util.*
import java.io.File
interface TargetableExternalStorage {
@@ -76,6 +74,10 @@ abstract class KonanPropertiesLoader(
dependencyProcessor!!.run()
}
fun downloadDependencies(archiveExtractor: ArchiveExtractor) {
dependencyProcessor!!.run(archiveExtractor)
}
// TODO: We may want to add caching to avoid repeated resolve.
override fun targetString(key: String): String? = properties.targetString(key, target)
override fun targetList(key: String): List<String> = properties.targetList(key, target)
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.util
import java.io.File
/**
* An interface for extracting archive files.
*/
interface ArchiveExtractor {
/**
* Extracts the contents of the specified archive file to the target directory.
*
* @param archive The archive file to extract.
* @param targetDirectory The directory where the contents of the archive will be extracted to.
* @param archiveType The type of the archive file.
*/
fun extract(archive: File, targetDirectory: File, archiveType: ArchiveType)
}
@@ -33,9 +33,8 @@ enum class ArchiveType(val fileExtension: String) {
}
}
class DependencyExtractor(
private val archiveType: ArchiveType
) {
class DependencyExtractor : ArchiveExtractor {
private fun extractTarGz(tarGz: File, targetDirectory: File) {
val tarProcess = ProcessBuilder().apply {
command("tar", "-xzf", tarGz.canonicalPath)
@@ -47,18 +46,19 @@ class DependencyExtractor(
finished && tarProcess.exitValue() != 0 ->
throw RuntimeException(
"Cannot extract archive with dependency: ${tarGz.canonicalPath}.\n" +
"Tar exit code: ${tarProcess.exitValue()}."
"Tar exit code: ${tarProcess.exitValue()}."
)
!finished -> {
tarProcess.destroy()
throw RuntimeException(
"Cannot extract archive with dependency: ${tarGz.canonicalPath}.\n" +
"Tar process hasn't finished in ${extractionTimeoutUntis.toSeconds(extractionTimeout)} sec.")
"Tar process hasn't finished in ${extractionTimeoutUntis.toSeconds(extractionTimeout)} sec."
)
}
}
}
fun extract(archive: File, targetDirectory: File) {
override fun extract(archive: File, targetDirectory: File, archiveType: ArchiveType) {
when (archiveType) {
ArchiveType.ZIP -> archive.toPath().unzipTo(targetDirectory.toPath())
ArchiveType.TAR_GZ -> extractTarGz(archive, targetDirectory)
@@ -109,7 +109,6 @@ class DependencyProcessor(
private var isInfoShown = false
private val downloader = DependencyDownloader(maxAttempts, attemptIntervalMs, customProgressCallback)
private val extractor = DependencyExtractor(archiveType)
constructor(dependenciesRoot: File,
properties: KonanPropertiesLoader,
@@ -172,7 +171,7 @@ class DependencyProcessor(
}
}
private fun downloadDependency(dependency: String, baseUrl: String) {
private fun downloadDependency(dependency: String, baseUrl: String, archiveExtractor: ArchiveExtractor) {
val depDir = File(dependenciesDirectory, dependency)
val depName = depDir.name
@@ -211,7 +210,7 @@ class DependencyProcessor(
downloader.download(url, archive)
}
println("Extracting dependency: $archive into $dependenciesDirectory")
extractor.extract(archive, dependenciesDirectory)
archiveExtractor.extract(archive, dependenciesDirectory, archiveType)
if (deleteArchives) {
archive.delete()
}
@@ -275,7 +274,7 @@ class DependencyProcessor(
}
}
fun run() {
fun run(archiveExtractor: ArchiveExtractor = DependencyExtractor()) {
// We need a lock that can be shared between different classloaders (KT-39781).
// TODO: Rework dependencies downloading to avoid storing the lock in the system properties.
val lock = System.getProperties().computeIfAbsent("kotlin.native.dependencies.lock") {
@@ -300,7 +299,7 @@ class DependencyProcessor(
DependencySource.Remote.Internal -> InternalServer.url
}
// TODO: consider using different caches for different remotes.
downloadDependency(dependency, baseUrl)
downloadDependency(dependency, baseUrl, archiveExtractor)
}
}
}