Improve logging in NativeCompilerDownloader

Issue #KT-31158 fixed
This commit is contained in:
Dmitriy Dolovov
2019-04-22 21:54:25 +07:00
parent 63f58b4a4a
commit d90b63d928
3 changed files with 137 additions and 22 deletions
@@ -22,22 +22,35 @@ import java.io.File
class NativeCompilerDownloader(
val project: Project,
val compilerVersion: KonanVersion = project.konanVersion
private val compilerVersion: KonanVersion = project.konanVersion
) {
internal companion object {
val DEFAULT_KONAN_VERSION: KonanVersion by lazy {
companion object {
internal val DEFAULT_KONAN_VERSION: KonanVersion by lazy {
KonanVersion.fromString(loadPropertyFromResources("project.properties", "kotlin.native.version"))
}
const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
private const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
}
val compilerDirectory: File
get() = DependencyDirectories.localKonanDir.resolve(dependencyNameWithVersion)
private val logger: Logger
get() = project.logger
private val simpleOsName: String
get() = HostManager.simpleOsName()
private val dependencyName: String
get() = "kotlin-native-$simpleOsName"
private val dependencyNameWithVersion: String
get() = "$dependencyName-$compilerVersion"
private val dependencyFileName: String
get() = "$dependencyNameWithVersion.$archiveExtension"
private val useZip
get() = HostManager.hostIsMingw
@@ -55,9 +68,9 @@ class NativeCompilerDownloader(
project.tarTree(archive)
}
private fun setupRepo(url: String): ArtifactRepository {
private fun setupRepo(repoUrl: String): ArtifactRepository {
return project.repositories.ivy { repo ->
repo.setUrl(url)
repo.setUrl(repoUrl)
repo.layout("pattern") {
val layout = it as IvyPatternRepositoryLayout
layout.artifact("[artifact]-[revision].[ext]")
@@ -73,41 +86,46 @@ class NativeCompilerDownloader(
}
private fun downloadAndExtract() {
val versionString = compilerVersion.toString()
val url = buildString {
val repoUrl = buildString {
append("$BASE_DOWNLOAD_URL/")
append(if (compilerVersion.meta == MetaVersion.DEV) "dev/" else "releases/")
append("$versionString/")
append("$compilerVersion/")
append(simpleOsName)
}
val dependencyUrl = "$repoUrl/$dependencyFileName"
val repo = setupRepo(url)
val repo = setupRepo(repoUrl)
val compilerDependency = project.dependencies.create(
mapOf(
"name" to "kotlin-native-$simpleOsName",
"version" to versionString,
"name" to dependencyName,
"version" to compilerVersion.toString(),
"ext" to archiveExtension
)
)
val configuration = project.configurations.detachedConfiguration(compilerDependency)
val archive = configuration.files.single()
logger.lifecycle("\nPlease wait while Kotlin/Native compiler $compilerVersion is being installed.")
val suffix = project.probeRemoteFileLength(dependencyUrl, probingTimeoutMs = 200)?.let { " (${formatContentLength(it)})" }.orEmpty()
logger.lifecycle("Download $dependencyUrl$suffix")
val archive = logger.lifecycleWithDuration("Download $dependencyUrl finished,") {
configuration.files.single()
}
logger.kotlinInfo("Using Kotlin/Native compiler archive: ${archive.absolutePath}")
logger.lifecycle("Unpacking Kotlin/Native compiler (version $versionString)...")
project.copy {
it.from(archiveFileTree(archive))
it.into(DependencyDirectories.localKonanDir)
logger.lifecycle("Unpack Kotlin/Native compiler to $compilerDirectory")
logger.lifecycleWithDuration("Unpack Kotlin/Native compiler to $compilerDirectory finished,") {
project.copy {
it.from(archiveFileTree(archive))
it.into(DependencyDirectories.localKonanDir)
}
}
removeRepo(repo)
}
val compilerDirectory: File
get() = DependencyDirectories.localKonanDir.resolve("kotlin-native-$simpleOsName-$compilerVersion")
fun downloadIfNeeded() {
if (KonanCompilerRunner(project).classpath.isEmpty) {
downloadAndExtract()
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.gradle.utils
import org.gradle.api.logging.Logger
internal fun formatDuration(milliseconds: Long): String {
var ms: Long = milliseconds
var s: Long = 0
var m: Long = 0
var h: Long = 0
if (ms >= 1000) {
s = ms / 1000
ms %= 1000
if (s >= 60) {
m = s / 60
s %= 60
if (m >= 60) {
h = m / 60
m %= 60
}
}
}
return buildString {
if (h > 0) append(h).append(" h ")
if (m > 0 || isNotEmpty()) append(m).append(" m ")
if (s > 0 || isNotEmpty()) append(s).append(" s ")
if (ms > 0 || isNotEmpty()) append(ms).append(" ms")
}
}
internal inline fun <T> Logger.lifecycleWithDuration(messagePrefix: String, action: () -> T): T {
val startTime = System.currentTimeMillis()
val result = action()
val finishTime = System.currentTimeMillis()
lifecycle("$messagePrefix took ${formatDuration(finishTime - startTime)}")
return result
}
internal fun formatContentLength(bytes: Long): String = when {
bytes < 0 -> "N/A"
bytes < 1024 -> "$bytes bytes"
else -> {
val kilobytes = bytes.toDouble() / 1024
when {
kilobytes < 1024 -> String.format("%.2f KB", kilobytes)
else -> {
val megabytes = kilobytes / 1024
when {
megabytes < 1024 -> String.format("%.2f MB", megabytes)
else -> {
val gigabytes = megabytes / 1024
String.format("%.2f GB", gigabytes)
}
}
}
}
}
}
@@ -5,7 +5,13 @@
package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import java.io.FileNotFoundException
import java.io.IOException
import java.net.HttpURLConnection
import java.net.SocketTimeoutException
import java.net.URL
import java.util.*
fun Any.loadPropertyFromResources(propFileName: String, property: String): String {
@@ -15,4 +21,29 @@ fun Any.loadPropertyFromResources(propFileName: String, property: String): Strin
inputStream.use { props.load(it) }
return props[property] as String
}
}
@Throws(IOException::class)
fun Project.probeRemoteFileLength(url: String, probingTimeoutMs: Int = 0): Long? {
val connection = URL(url).openConnection()
if (connection !is HttpURLConnection) {
logger.kotlinDebug(::probeRemoteFileLength.name + "($url, $probingTimeoutMs): Failed to obtain content-length. Likely not an HTTP-based URL. URL connection class is ${connection::class.java}.")
return null
}
return try {
connection.requestMethod = "HEAD"
connection.connectTimeout = probingTimeoutMs
connection.readTimeout = probingTimeoutMs
connection.contentLengthLong.takeIf { it >= 0 }
} catch (e: SocketTimeoutException) {
if (probingTimeoutMs == 0)
throw e
else {
logger.kotlinDebug(::probeRemoteFileLength.name + "($url, $probingTimeoutMs): Failed to obtain content-length during the probing timeout.")
null
}
} finally {
connection.disconnect()
}
}