dependencies: Track downloading in a separate thread

This commit is contained in:
Ilya Matveev
2017-08-22 17:55:59 +07:00
committed by ilmat192
parent 24a87415d7
commit 7116801dc6
3 changed files with 67 additions and 19 deletions
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.config.addKotlinSourceRoots
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.TargetManager
import org.jetbrains.kotlin.utils.KotlinPaths
import java.io.File
import kotlin.reflect.KFunction
class K2Native : CLICompiler<K2NativeCompilerArguments>() {
-1
View File
@@ -21,7 +21,6 @@ import groovy.transform.stc.FirstParam
import groovy.transform.stc.FromString
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.DependencyProcessor
import static org.jetbrains.kotlin.konan.target.KonanTarget.*
import org.jetbrains.kotlin.konan.properties.KonanProperties
import org.jetbrains.kotlin.konan.properties.*
@@ -6,6 +6,10 @@ import java.net.URL
import java.net.URLConnection
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.thread
import kotlin.concurrent.withLock
class DependencyDownloader(
var maxAttempts: Int = DEFAULT_MAX_ATTEMPTS,
@@ -21,29 +25,77 @@ class DependencyDownloader(
RETURN_EXISTING
}
class DownloadingProgress(@Volatile var currentBytes: Long, val totalBytes: Long) {
@Volatile var done: Boolean = false
private set
@Volatile var exception: Throwable? = null
private set
private val lock = ReentrantLock()
private val condition = lock.newCondition()
val doneCorrectly: Boolean
get() = done && exception != null
fun update(readBytes: Int) { currentBytes += readBytes }
fun done() = lock.withLock {
done = true
condition.signalAll()
}
fun done(e: Throwable) = lock.withLock {
done = true
exception = e
condition.signalAll()
}
fun trackProgress(interval: Long,
intervalTimeUnit: TimeUnit = TimeUnit.MILLISECONDS,
action: (progress: DownloadingProgress) -> Unit) =
lock.withLock {
action(this)
while (!done) {
condition.await(interval, intervalTimeUnit)
action(this)
}
}
}
private fun doDownload(originalUrl: URL,
connection: URLConnection,
tmpFile: File,
currentBytes: Long,
totalBytes: Long,
append: Boolean) {
@Suppress("NAME_SHADOWING")
var currentBytes = currentBytes
connection.getInputStream().use { from ->
FileOutputStream(tmpFile, append).use { to ->
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
var read = from.read(buffer)
while (read != -1) {
to.write(buffer, 0, read)
currentBytes += read
updateProgressMsg(originalUrl.toString(), currentBytes, totalBytes)
read = from.read(buffer)
}
if (currentBytes != totalBytes) {
throw EOFException("The stream closed before end of downloading.")
val progress = DownloadingProgress(currentBytes, totalBytes)
// TODO: Implement multi-thread downloading + use some sort of thread pool.
thread {
Thread.setDefaultUncaughtExceptionHandler { _, throwable -> progress.done(throwable) }
connection.getInputStream().use { from ->
FileOutputStream(tmpFile, append).use { to ->
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
var read = from.read(buffer)
while (read != -1) {
to.write(buffer, 0, read)
progress.update(read)
read = from.read(buffer)
}
if (currentBytes != totalBytes) {
throw EOFException("The stream closed before end of downloading.")
}
progress.done()
}
}
}
progress.trackProgress(1000) {
updateProgressMsg(originalUrl.toString(), it.currentBytes, it.totalBytes)
}
if (!progress.doneCorrectly) {
throw progress.exception!!
}
}
private fun tryHttpDownload(originalUrl: URL, connection: HttpURLConnection, tmpFile: File) {
@@ -82,7 +134,7 @@ class DependencyDownloader(
/** Performs an attempt to download a specified file into the specified location */
private fun tryDownload(url: URL, tmpFile: File) {
var connection = url.openConnection()
val connection = url.openConnection()
if (connection is HttpURLConnection) {
tryHttpDownload(url, connection, tmpFile)
} else {
@@ -152,8 +204,6 @@ class DependencyDownloader(
print("\rDownloading dependency: $url (${currentBytes.humanReadable}/${totalBytes.humanReadable}). ")
}
companion object {
const val DEFAULT_MAX_ATTEMPTS = 10
const val DEFAULT_ATTEMPT_INTERVAL_MS = 3000L