tools: Use dependency cache

This commit is contained in:
Ilya Matveev
2017-03-28 11:09:21 +07:00
committed by ilmat192
parent 2d51a7bab7
commit 9308f86223
2 changed files with 43 additions and 27 deletions
+3 -3
View File
@@ -45,11 +45,11 @@ void prepareDependenciesDir(File testDependencies) {
project.delete testDependencies project.delete testDependencies
testDependencies.mkdirs() testDependencies.mkdirs()
// We don't download big clang dependency in this test - only sysroots. // We don't download big clang dependency in this test - only sysroots.
project.copy { /*project.copy {
from project.findProject(":dependencies").file("all") from project.findProject(":dependencies").file("all")
into testDependencies into testDependencies
include "clang*.tar.gz/**" include "clang*.tar.gz/**"
} }*/
} }
kotlinNativeInterop { kotlinNativeInterop {
@@ -104,7 +104,7 @@ task testParallel(type: DefaultTask) {
task.executeTest() task.executeTest()
// The helper prints messages when it is downloading. // The helper prints messages when it is downloading.
// We check that there is only one downloading using compilation logs. // We check that there is only one downloading using compilation logs.
if (file("${task.buildExePath()}.compilation.log").text.contains("Download dependency")) { if (file("${task.buildExePath()}.compilation.log").text.contains("Extract dependency")) {
downloadCnt.incrementAndGet() downloadCnt.incrementAndGet()
} }
}) })
@@ -8,52 +8,70 @@ import kotlin.concurrent.thread
// TODO: Try to use some dependency management system (Ivy?) // TODO: Try to use some dependency management system (Ivy?)
class DependencyDownloader(dependenciesRoot: File, val properties: Properties, val dependencies: List<String>) { class DependencyDownloader(dependenciesRoot: File, val properties: Properties, val dependencies: List<String>) {
val dependenciesRoot = dependenciesRoot.apply { mkdirs() } val dependenciesDirectory = dependenciesRoot.apply { mkdirs() }
val cacheDirectory = System.getProperty("user.home")?.let {
File("$it/.konan/cache").apply { mkdirs() }
} ?: dependenciesRoot
val lockFile = File(dependenciesRoot, ".lock").apply { createNewFile() } val lockFile = File(cacheDirectory, ".lock").apply { if (!exists()) createNewFile() }
val listFile = File(dependenciesRoot, ".downloaded")
val dependenciesUrl: String = val dependenciesUrl: String =
properties.getProperty("dependenciesUrl", "https://jetbrains.bintray.com/kotlin-native-dependencies") properties.getProperty("dependenciesUrl", "https://jetbrains.bintray.com/kotlin-native-dependencies")
var isInfoShown = false var isInfoShown = false
private fun File.containsLine(line: String): Boolean { class DependencyFile(directory: File, fileName: String) {
if (!exists()) { val file = File(directory, fileName).apply { createNewFile() }
return false private val dependencies_ = file.readLines().toMutableSet()
val dependencies = dependencies_.toSet()
fun contains(dependency: String) = dependencies_.contains(dependency)
fun add(dependency: String) = dependencies_.add(dependency)
fun addWithSave(dependency: String) {
add(dependency)
save()
} }
var result = false
listFile.forEachLine { fun save() {
if (!result && it == line) { val writer = file.writer()
result = true writer.use {
dependencies_.forEach {
writer.write(it)
writer.write("\n")
}
} }
} }
return result
} }
private fun processDependency(dependency: String) { private fun processDependency(dependency: String) {
val depDir = File(dependenciesRoot, dependency) val depDir = File(dependenciesDirectory, dependency)
val depName = depDir.name val depName = depDir.name
val inListFile = listFile.containsLine(depName)
if (inListFile && depDir.exists()) { val cachedDependencies = DependencyFile(cacheDirectory, ".cached")
val extractedDependencies = DependencyFile(dependenciesDirectory, ".extracted")
if (extractedDependencies.contains(depName) && depDir.exists()) {
return return
} }
if (!isInfoShown) { if (!isInfoShown) {
println("Downloading native dependencies (LLVM, sysroot etc). This is one-time action performing only for the first run of the compiler.") println("Downloading native dependencies (LLVM, sysroot etc). This is one-time action performing only for the first run of the compiler.")
isInfoShown = true isInfoShown = true
} }
val downloaded = download(depName)
extract(downloaded) val archive = File(cacheDirectory.canonicalPath, "$depName.tar.gz")
if (!inListFile) { if (!cachedDependencies.contains(depName) || !archive.exists()) {
listFile.appendText("$depName\n") download(depName, archive)
cachedDependencies.addWithSave(depName)
} }
extract(archive, dependenciesDirectory)
extractedDependencies.addWithSave(depName)
} }
private fun extract(tarGz: File) { private fun extract(tarGz: File, target: File) {
println("Extract dependency: ${tarGz.canonicalPath}") println("Extract dependency: ${tarGz.canonicalPath} in ${target.canonicalPath}")
val tarProcess = ProcessBuilder().apply { val tarProcess = ProcessBuilder().apply {
command("tar", "-xzf", "${tarGz.canonicalPath}") command("tar", "-xzf", "${tarGz.canonicalPath}")
directory(tarGz.parentFile) directory(target)
}.start() }.start()
tarProcess.waitFor() tarProcess.waitFor()
if (tarProcess.exitValue() != 0) { if (tarProcess.exitValue() != 0) {
@@ -78,8 +96,7 @@ class DependencyDownloader(dependenciesRoot: File, val properties: Properties, v
print("\rDownload dependency: $url (${currentBytes.humanReadable}/${totalBytes.humanReadable}). ") print("\rDownload dependency: $url (${currentBytes.humanReadable}/${totalBytes.humanReadable}). ")
} }
private fun download(dependencyName: String): File { private fun download(dependencyName: String, outputFile: File) {
val outputFile = File(dependenciesRoot.canonicalPath, "$dependencyName.tar.gz")
if (!outputFile.exists()) { if (!outputFile.exists()) {
val url = URL("$dependenciesUrl/$dependencyName.tar.gz") val url = URL("$dependenciesUrl/$dependencyName.tar.gz")
val connection = url.openConnection() val connection = url.openConnection()
@@ -118,7 +135,6 @@ class DependencyDownloader(dependenciesRoot: File, val properties: Properties, v
throw RuntimeException("Cannot download dependency: $url", downloadError) throw RuntimeException("Cannot download dependency: $url", downloadError)
} }
} }
return outputFile
} }
fun run() { fun run() {