dependencies: Move dependency downloader into shared project
This commit is contained in:
+1
-1
@@ -187,7 +187,7 @@ private fun runCmd(command: Array<String>, workDir: File, verbose: Boolean = fal
|
||||
|
||||
private fun maybeExecuteHelper(dependenciesRoot: String, properties: Properties, dependencies: List<String>) {
|
||||
try {
|
||||
val kClass = Class.forName("org.jetbrains.kotlin.konan.Helper0").kotlin
|
||||
val kClass = Class.forName("org.jetbrains.kotlin.konan.util.Helper0").kotlin
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val ctor = kClass.constructors.single() as KFunction<Runnable>
|
||||
val result = ctor.call(dependenciesRoot, properties, dependencies)
|
||||
|
||||
@@ -33,28 +33,9 @@ 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
|
||||
|
||||
// TODO: Don't use reflection?
|
||||
private fun maybeExecuteHelper(targetName: String) {
|
||||
try {
|
||||
val kClass = Class.forName("org.jetbrains.kotlin.konan.Helper0").kotlin
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val ctor = kClass.constructors.single() as KFunction<Runnable>
|
||||
val distribution = Distribution(TargetManager(targetName))
|
||||
val result = ctor.call(
|
||||
distribution.dependenciesDir,
|
||||
distribution.properties,
|
||||
distribution.dependencies
|
||||
)
|
||||
result.run()
|
||||
} catch (notFound: ClassNotFoundException) {
|
||||
// Just ignore, no helper.
|
||||
} catch (e: Throwable) {
|
||||
throw IllegalStateException("Cannot download dependencies.", e)
|
||||
}
|
||||
}
|
||||
|
||||
class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
|
||||
override fun doExecute(@NotNull arguments: K2NativeCompilerArguments, @NotNull configuration: CompilerConfiguration, @NotNull rootDisposable: Disposable, @Nullable paths: KotlinPaths?): ExitCode {
|
||||
@@ -85,7 +66,6 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
return this?.asList<String>() ?: listOf<String>()
|
||||
}
|
||||
|
||||
|
||||
// It is executed before doExecute().
|
||||
override fun setupPlatformSpecificArgumentsAndServices(
|
||||
configuration: CompilerConfiguration,
|
||||
@@ -152,8 +132,6 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
put(ENABLE_ASSERTIONS, arguments.enableAssertions)
|
||||
}
|
||||
}
|
||||
|
||||
maybeExecuteHelper(arguments.target ?: "host")
|
||||
}
|
||||
|
||||
override fun createArguments(): K2NativeCompilerArguments {
|
||||
|
||||
+2
-2
@@ -18,11 +18,11 @@
|
||||
// Example startup helper for Kotlin N compiler. Compile to JAR and add it to
|
||||
// Kotlin N classpath - it will get loaded and executed automatically.
|
||||
//
|
||||
package org.jetbrains.kotlin.konan
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import java.util.*
|
||||
|
||||
// Name it CompilerHelper0 so that it get loaded.
|
||||
// Name it Helper0 so that it get loaded.
|
||||
class Helper0Disabled(val dependenciesDir: String,
|
||||
val properties: Properties,
|
||||
val dependencies: List<String>) : Runnable {
|
||||
|
||||
+10
-2
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
import org.jetbrains.kotlin.konan.target.TargetManager.*
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
|
||||
import org.jetbrains.kotlin.konan.util.DependencyProcessor
|
||||
|
||||
class KonanConfig(val project: Project, val configuration: CompilerConfiguration) {
|
||||
|
||||
@@ -47,9 +48,16 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
error("Target $target is not available on the ${TargetManager.host} host")
|
||||
}
|
||||
}
|
||||
|
||||
private fun Distribution.prepareDependencies() {
|
||||
DependencyProcessor(java.io.File(dependenciesDir), targetProperties).run()
|
||||
}
|
||||
|
||||
internal val distribution = Distribution(targetManager,
|
||||
configuration.get(KonanConfigKeys.PROPERTY_FILE),
|
||||
configuration.get(KonanConfigKeys.RUNTIME_FILE))
|
||||
configuration.get(KonanConfigKeys.PROPERTY_FILE),
|
||||
configuration.get(KonanConfigKeys.RUNTIME_FILE)).apply {
|
||||
prepareDependencies()
|
||||
}
|
||||
|
||||
private val produce = configuration.get(KonanConfigKeys.PRODUCE)!!
|
||||
private val suffix = produce.suffix(targetManager.target)
|
||||
|
||||
@@ -22,7 +22,8 @@ dependenciesUrl = http://download.jetbrains.com/kotlin/native
|
||||
airplaneMode = false
|
||||
|
||||
downloadingAttempts = 10
|
||||
downloadingAttemptPauseMs = 3000
|
||||
downloadingAttemptIntervalMs = 3000
|
||||
homeDependencyCache = .konan/cache
|
||||
|
||||
llvmDebugOptFlags = -O0
|
||||
|
||||
|
||||
@@ -143,7 +143,6 @@ task list_dist(dependsOn: "listDist")
|
||||
|
||||
task distCompiler(type: Copy) {
|
||||
dependsOn ':backend.native:jars'
|
||||
dependsOn ':tools:helpers:jar'
|
||||
dependsOn ':utilities:jar'
|
||||
dependsOn ':klib:jar'
|
||||
dependsOn ':shared:jar'
|
||||
@@ -212,11 +211,6 @@ task distCompiler(type: Copy) {
|
||||
from(konanPropertiesFile) {
|
||||
into('konan')
|
||||
}
|
||||
|
||||
// TODO: check if we use native libraries copied to dist (see above) or not.
|
||||
from(project(':tools:helpers').file('build/libs')) {
|
||||
into('konan/lib')
|
||||
}
|
||||
}
|
||||
|
||||
task listDist(type: Exec) {
|
||||
|
||||
@@ -100,8 +100,6 @@ abstract class KonanTest extends JavaExec {
|
||||
try {
|
||||
main = 'org.jetbrains.kotlin.cli.bc.K2NativeKt'
|
||||
classpath = project.configurations.cli_bc
|
||||
// TODO: Remove helpers classpath when downloading is moved into 'shared' project.
|
||||
classpath += project.project(":tools:helpers").sourceSets.main.runtimeClasspath
|
||||
enableAssertions = true
|
||||
args = ["-output", output,
|
||||
*filesToCompile,
|
||||
|
||||
+1
-2
@@ -79,11 +79,10 @@ KOTLIN_JAR="${KONAN_HOME}/konan/lib/kotlin-compiler.jar"
|
||||
STUB_GENERATOR_JAR="${KONAN_HOME}/konan/lib/StubGenerator.jar"
|
||||
INTEROP_INDEXER_JAR="${KONAN_HOME}/konan/lib/Indexer.jar"
|
||||
INTEROP_JAR="${KONAN_HOME}/konan/lib/Runtime.jar"
|
||||
HELPERS_JAR="${KONAN_HOME}/konan/lib/helpers.jar"
|
||||
SHARED_JAR="${KONAN_HOME}/konan/lib/shared.jar"
|
||||
KLIB_JAR="${KONAN_HOME}/konan/lib/klib.jar"
|
||||
UTILITIES_JAR="${KONAN_HOME}/konan/lib/utilities.jar"
|
||||
KONAN_CLASSPATH="$KOTLIN_JAR:$INTEROP_JAR:$STUB_GENERATOR_JAR:$INTEROP_INDEXER_JAR:$KONAN_JAR:$HELPERS_JAR:$KLIB_JAR:$UTILITIES_JAR:$SHARED_JAR"
|
||||
KONAN_CLASSPATH="$KOTLIN_JAR:$INTEROP_JAR:$STUB_GENERATOR_JAR:$INTEROP_INDEXER_JAR:$KONAN_JAR:$KLIB_JAR:$UTILITIES_JAR:$SHARED_JAR"
|
||||
TOOL_CLASS=org.jetbrains.kotlin.cli.utilities.MainKt
|
||||
|
||||
LIBCLANG_DISABLE_CRASH_RECOVERY=1 \
|
||||
|
||||
Vendored
+14
-18
@@ -16,7 +16,12 @@
|
||||
|
||||
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.ClosureSignatureHint
|
||||
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.*
|
||||
@@ -166,23 +171,11 @@ class TgzNativeDep extends NativeDep {
|
||||
|
||||
class HelperNativeDep extends TgzNativeDep {
|
||||
|
||||
int maxAttempts = Integer.parseInt(
|
||||
project.rootProject.ext.konanProperties['downloadingAttempts'].toString())
|
||||
long attemptPauseMs = Long.parseLong(
|
||||
project.rootProject.ext.konanProperties['downloadingAttemptPauseMs'].toString())
|
||||
|
||||
public HelperNativeDep() {
|
||||
dependsOn(':tools:helpers:jar')
|
||||
}
|
||||
Properties konanProperties = new Properties()
|
||||
|
||||
@TaskAction
|
||||
public void downloadAndExtract() {
|
||||
project.javaexec {
|
||||
main = "org.jetbrains.kotlin.konan.MainKt"
|
||||
classpath += project.findProject(':tools:helpers').getConfigurations().getByName("runtime")
|
||||
classpath += project.findProject(':tools:helpers').getConfigurations().getByName("runtime").artifacts.files
|
||||
args baseOutDir.canonicalPath, baseUrl, maxAttempts, attemptPauseMs, baseName
|
||||
}
|
||||
new DependencyProcessor(baseOutDir, konanProperties, [baseName], baseUrl).run()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +188,8 @@ enum DependencyKind {
|
||||
|
||||
|
||||
DependencyKind(String name,
|
||||
@ClosureParams(KonanProperties.class) Closure<String> dirGetter,
|
||||
@ClosureParams(KonanTarget.class) Closure<String> propertyNameGetter =
|
||||
@ClosureParams(value = FromString.class, options = "KonanProperties") Closure<String> dirGetter,
|
||||
@ClosureParams(value = FromString.class, options = "KonanTarget") Closure<String> propertyNameGetter =
|
||||
{target -> "${target.userName}${name.capitalize()}Dir"}) {
|
||||
this.name = name
|
||||
this.dirGetter = dirGetter
|
||||
@@ -225,8 +218,11 @@ TargetManager.enabled.each { target ->
|
||||
)
|
||||
|
||||
konanProperties.dependencies.each { dependency ->
|
||||
task "${target.userName}-${dependency}"(type: HelperNativeDep) {
|
||||
baseName = dependency
|
||||
if (tasks.findByName(dependency) == null) {
|
||||
task "${dependency}"(type: HelperNativeDep) {
|
||||
baseName = dependency
|
||||
it.konanProperties = rootProject.ext.konanProperties
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,5 @@ include ':runtime'
|
||||
include ':common'
|
||||
include ':backend.native:tests'
|
||||
include ':shared'
|
||||
include ':tools:helpers'
|
||||
include ':tools:kotlin-native-gradle-plugin'
|
||||
include ':utilities'
|
||||
+10
-2
@@ -182,7 +182,7 @@ fun Path.recursiveCopyTo(destPath: Path) {
|
||||
val relative = sourcePath.relativize(oldPath)
|
||||
val destFs = destPath.getFileSystem()
|
||||
// We are copying files between file systems,
|
||||
// so pass the relative path through the Sting.
|
||||
// so pass the relative path through the String.
|
||||
val newPath = destFs.getPath(destPath.toString(), relative.toString())
|
||||
|
||||
// File systems don't allow replacing an existing root.
|
||||
@@ -195,7 +195,7 @@ fun Path.recursiveCopyTo(destPath: Path) {
|
||||
fun bufferedReader(errorStream: InputStream?) = BufferedReader(InputStreamReader(errorStream))
|
||||
|
||||
// stdlib `use` function adapted for AutoCloseable.
|
||||
private inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
|
||||
inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
|
||||
var closed = false
|
||||
try {
|
||||
return block(this)
|
||||
@@ -212,3 +212,11 @@ private inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Path.unzipTo(directory: Path) {
|
||||
val zipUri = URI.create("jar:" + this.toUri())
|
||||
FileSystems.newFileSystem(zipUri, emptyMap<String, Any?>(), null).use { zipfs ->
|
||||
val zipPath = zipfs.getPath("/")
|
||||
zipPath.recursiveCopyTo(directory)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import java.io.EOFException
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
class DependencyDownloader(
|
||||
var maxAttempts: Int = DEFAULT_MAX_ATTEMPTS,
|
||||
var attemptIntervalMs: Long = DEFAULT_ATTEMPT_INTERVAL_MS) {
|
||||
|
||||
enum class ReplacingMode {
|
||||
/** Redownload the file and replace the existing one. */
|
||||
REPLACE,
|
||||
/** Throw FileAlreadyExistsException */
|
||||
THROW,
|
||||
/** Don't download the file and return the existing one*/
|
||||
RETURN_EXISTING
|
||||
}
|
||||
|
||||
/** Performs an attempt to download a specified file into the specified location */
|
||||
fun tryDownload(url: URL, dstFile: File) {
|
||||
val connection = url.openConnection()
|
||||
val totalBytes = connection.contentLengthLong
|
||||
var currentBytes = 0L
|
||||
|
||||
try {
|
||||
url.openStream().use { from ->
|
||||
FileOutputStream(dstFile, false).use { to ->
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var read = from.read(buffer)
|
||||
while (read != -1) {
|
||||
to.write(buffer, 0, read)
|
||||
currentBytes += read
|
||||
updateProgressMsg(url.toString(), currentBytes, totalBytes)
|
||||
read = from.read(buffer)
|
||||
}
|
||||
if (currentBytes != totalBytes) {
|
||||
throw EOFException("The stream closed before end of downloading.")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
dstFile.delete()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/** Downloads a file from [source] url to [destination]. Returns [destination]. */
|
||||
fun download(source: URL,
|
||||
destination: File,
|
||||
replace: ReplacingMode = ReplacingMode.RETURN_EXISTING): File {
|
||||
|
||||
if (destination.exists()) {
|
||||
@Suppress("NON_EXHAUSTIVE_WHEN")
|
||||
when (replace) {
|
||||
ReplacingMode.RETURN_EXISTING -> return destination
|
||||
ReplacingMode.THROW -> throw FileAlreadyExistsException(destination)
|
||||
// TODO: What if dst is a directory?
|
||||
}
|
||||
}
|
||||
// TODO: resuming must be here
|
||||
val tmpFile = File("${destination.canonicalPath}.$TMP_SUFFIX")
|
||||
|
||||
var attempt = 1
|
||||
var waitTime = 0L
|
||||
while (true) {
|
||||
try {
|
||||
tryDownload(source, tmpFile)
|
||||
break
|
||||
} catch (e: IOException) {
|
||||
if (attempt >= maxAttempts) {
|
||||
throw e
|
||||
}
|
||||
attempt++
|
||||
waitTime += attemptIntervalMs
|
||||
println("Cannot download a dependency: $e\n" +
|
||||
"Wait ${waitTime.toDouble() / 1000} sec and try again (attempt: $attempt/$maxAttempts).")
|
||||
// TODO: Wait better
|
||||
Thread.sleep(waitTime)
|
||||
}
|
||||
}
|
||||
|
||||
Files.move(tmpFile.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
println("Done.")
|
||||
return destination
|
||||
}
|
||||
|
||||
private val Long.humanReadable: String
|
||||
get() {
|
||||
if (this < 0) {
|
||||
return "-"
|
||||
}
|
||||
if (this < 1024) {
|
||||
return "$this bytes"
|
||||
}
|
||||
val exp = (Math.log(this.toDouble()) / Math.log(1024.0)).toInt()
|
||||
val prefix = "kMGTPE"[exp-1]
|
||||
return "%.1f %siB".format(this / Math.pow(1024.0, exp.toDouble()), prefix)
|
||||
}
|
||||
|
||||
private fun updateProgressMsg(url: String, currentBytes: Long, totalBytes: Long) {
|
||||
print("\rDownload dependency: $url (${currentBytes.humanReadable}/${totalBytes.humanReadable}). ")
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_MAX_ATTEMPTS = 10
|
||||
const val DEFAULT_ATTEMPT_INTERVAL_MS = 3000L
|
||||
|
||||
const val TMP_SUFFIX = "part"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.unzipTo
|
||||
import java.io.File
|
||||
|
||||
|
||||
class DependencyExtractor {
|
||||
internal val useZip = System.getProperty("os.name").startsWith("Windows")
|
||||
|
||||
internal val archiveExtension = if (useZip) {
|
||||
"zip"
|
||||
} else {
|
||||
"tar.gz"
|
||||
}
|
||||
|
||||
private fun extractTarGz(tarGz: File, targetDirectory: File) {
|
||||
println("Extract dependency: ${tarGz.canonicalPath} in ${targetDirectory.canonicalPath}")
|
||||
val tarProcess = ProcessBuilder().apply {
|
||||
command("tar", "-xzf", tarGz.canonicalPath)
|
||||
directory(targetDirectory)
|
||||
}.start()
|
||||
tarProcess.waitFor()
|
||||
if (tarProcess.exitValue() != 0) {
|
||||
throw RuntimeException("Cannot extract archive with dependency: ${tarGz.canonicalPath}")
|
||||
}
|
||||
}
|
||||
|
||||
fun extract(archive: File, targetDirectory: File) {
|
||||
if (useZip) {
|
||||
archive.toPath().unzipTo(targetDirectory.toPath())
|
||||
} else {
|
||||
extractTarGz(archive, targetDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.use
|
||||
import org.jetbrains.kotlin.konan.properties.KonanProperties
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.RandomAccessFile
|
||||
import java.net.URL
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
private val Properties.dependenciesUrl : String
|
||||
get() = getProperty("dependenciesUrl")
|
||||
?: throw IllegalStateException("No such property in konan.properties: dependenciesUrl")
|
||||
|
||||
private val Properties.airplaneMode : Boolean
|
||||
get() = getProperty("airplaneMode")?.toBoolean() ?: false
|
||||
|
||||
private val Properties.downloadingAttempts : Int
|
||||
get() = getProperty("downloadingAttempts")?.toInt()
|
||||
?: DependencyDownloader.DEFAULT_MAX_ATTEMPTS
|
||||
|
||||
private val Properties.downloadingAttemptIntervalMs : Long
|
||||
get() = getProperty("downloadingAttemptPauseMs")?.toLong()
|
||||
?: DependencyDownloader.DEFAULT_ATTEMPT_INTERVAL_MS
|
||||
|
||||
private val Properties.homeDependencyCache : String
|
||||
get() = getProperty("homeDependencyCache") ?: DependencyProcessor.DEFAULT_HOME_DEPENDENCY_CACHE
|
||||
|
||||
|
||||
private val KonanProperties.dependenciesUrl : String get() = properties.dependenciesUrl
|
||||
private val KonanProperties.airplaneMode : Boolean get() = properties.airplaneMode
|
||||
private val KonanProperties.downloadingAttempts : Int get() = properties.downloadingAttempts
|
||||
private val KonanProperties.downloadingAttemptIntervalMs : Long get() = properties.downloadingAttemptIntervalMs
|
||||
private val KonanProperties.homeDependencyCache : String get() = properties.homeDependencyCache
|
||||
|
||||
// TODO: Try to use some dependency management system (Ivy?)
|
||||
// TODO: Maybe rename.
|
||||
/**
|
||||
* Inspects [dependencies] and downloads all the missing ones into [dependenciesDirectory] from [dependenciesUrl].
|
||||
* If [airplaneMode] is true will throw a RuntimeException instead of downloading.
|
||||
*/
|
||||
class DependencyProcessor(dependenciesRoot: File,
|
||||
val dependenciesUrl: String,
|
||||
val dependencies: Collection<String>,
|
||||
homeDependencyCache: String = DEFAULT_HOME_DEPENDENCY_CACHE,
|
||||
val airplaneMode: Boolean = false,
|
||||
maxAttempts: Int = DependencyDownloader.DEFAULT_MAX_ATTEMPTS,
|
||||
attemptIntervalMs: Long = DependencyDownloader.DEFAULT_ATTEMPT_INTERVAL_MS) {
|
||||
|
||||
val dependenciesDirectory = dependenciesRoot.apply { mkdirs() }
|
||||
val cacheDirectory = System.getProperty("user.home")?.let {
|
||||
Paths.get(it).resolve(homeDependencyCache).toFile().apply { mkdirs() }
|
||||
} ?: dependenciesRoot
|
||||
|
||||
val lockFile = File(cacheDirectory, ".lock").apply { if (!exists()) createNewFile() }
|
||||
|
||||
private var isInfoShown = false
|
||||
|
||||
// TOOO: Rename pause -> interval
|
||||
private val downloader = DependencyDownloader(maxAttempts, attemptIntervalMs)
|
||||
private val extractor = DependencyExtractor()
|
||||
|
||||
private val archiveExtension get() = extractor.archiveExtension
|
||||
|
||||
constructor(dependenciesRoot: File,
|
||||
properties: KonanProperties,
|
||||
dependenciesUrl: String = properties.dependenciesUrl) : this(
|
||||
dependenciesRoot,
|
||||
properties.properties,
|
||||
properties.dependencies,
|
||||
dependenciesUrl)
|
||||
|
||||
constructor(dependenciesRoot: File,
|
||||
properties: Properties,
|
||||
dependencies: List<String>,
|
||||
dependenciesUrl: String = properties.dependenciesUrl) : this(
|
||||
dependenciesRoot,
|
||||
dependenciesUrl,
|
||||
dependencies,
|
||||
airplaneMode = properties.airplaneMode,
|
||||
maxAttempts = properties.downloadingAttempts,
|
||||
attemptIntervalMs = properties.downloadingAttemptIntervalMs)
|
||||
|
||||
|
||||
class DependencyFile(directory: File, fileName: String) {
|
||||
val file = File(directory, fileName).apply { createNewFile() }
|
||||
private val dependencies = file.readLines().toMutableSet()
|
||||
|
||||
fun contains(dependency: String) = dependencies.contains(dependency)
|
||||
fun add(dependency: String) = dependencies.add(dependency)
|
||||
fun addWithSave(dependency: String) {
|
||||
add(dependency)
|
||||
save()
|
||||
}
|
||||
|
||||
fun save() {
|
||||
val writer = file.writer()
|
||||
writer.use {
|
||||
dependencies.forEach {
|
||||
writer.write(it)
|
||||
writer.write("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processDependency(dependency: String) {
|
||||
val depDir = File(dependenciesDirectory, dependency)
|
||||
val depName = depDir.name
|
||||
|
||||
val extractedDependencies = DependencyFile(dependenciesDirectory, ".extracted")
|
||||
if (extractedDependencies.contains(depName) &&
|
||||
depDir.exists() &&
|
||||
depDir.isDirectory &&
|
||||
depDir.list().isNotEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isInfoShown) {
|
||||
println("Downloading native dependencies (LLVM, sysroot etc). This is a one-time action performed only on the first run of the compiler.")
|
||||
isInfoShown = true
|
||||
}
|
||||
val fileName = "$depName.$archiveExtension"
|
||||
val archive = cacheDirectory.resolve(fileName)
|
||||
val url = URL("$dependenciesUrl/$fileName")
|
||||
|
||||
if (!archive.exists()) {
|
||||
if (airplaneMode) {
|
||||
throw FileNotFoundException("""
|
||||
Cannot find a dependency locally: $dependency.
|
||||
Set `airplaneMode = false` in konan.properties to download it.
|
||||
""".trimIndent())
|
||||
} else {
|
||||
downloader.download(url, archive)
|
||||
}
|
||||
}
|
||||
extractor.extract(archive, dependenciesDirectory)
|
||||
extractedDependencies.addWithSave(depName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val lock = ReentrantLock()
|
||||
|
||||
const val DEFAULT_HOME_DEPENDENCY_CACHE = ".konan/cache"
|
||||
}
|
||||
|
||||
fun run() = lock.withLock {
|
||||
RandomAccessFile(lockFile, "rw").channel.lock().use {
|
||||
dependencies.forEach {
|
||||
processDependency(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-9
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
@@ -24,15 +24,10 @@ class Helper0(val dependenciesDir: String,
|
||||
val dependencies: List<String>): Runnable {
|
||||
|
||||
override fun run() {
|
||||
DependencyDownloader(
|
||||
File(dependenciesDir),
|
||||
properties.getProperty("dependenciesUrl", "https://download.jetbrains.com/kotlin/native"),
|
||||
DependencyProcessor(File(dependenciesDir),
|
||||
properties,
|
||||
dependencies,
|
||||
airplaneMode = properties.getProperty("airplaneMode")?.toBoolean() ?: false,
|
||||
maxAttempts = properties.getProperty("downloadingAttempts")?.toInt()
|
||||
?: DependencyDownloader.DEFAULT_MAX_ATTEMPTS,
|
||||
attemptPauseMs = properties.getProperty("downloadingAttemptPauseMs")?.toLong()
|
||||
?: DependencyDownloader.DEFAULT_ATTEMPT_PAUSE_MS
|
||||
properties.getProperty("dependenciesUrl", "https://download.jetbrains.com/kotlin/native")
|
||||
).run()
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.jetbrains.kotlin.NativeInteropPlugin
|
||||
import org.jetbrains.kotlin.RunInteropKonanTest
|
||||
import org.jetbrains.kotlin.RunKonanTest
|
||||
import org.jetbrains.kotlin.TestFailedException
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
buildscript {
|
||||
apply from: "$rootDir/gradle/kotlinGradlePlugin.gradle"
|
||||
}
|
||||
|
||||
// Copied from backend.native project. =====
|
||||
repositories {
|
||||
maven { url kotlinCompilerRepo }
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
// kotlin-compiler module includes Kotlin runtime bundled;
|
||||
// make Gradle aware of this to avoid multiple Kotlin runtimes in classpath:
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute module('org.jetbrains.kotlin:kotlin-runtime') with module(kotlinCompilerModule)
|
||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib') with module(kotlinCompilerModule)
|
||||
substitute module('org.jetbrains.kotlin:kotlin-reflect') with module(kotlinCompilerModule)
|
||||
}
|
||||
}
|
||||
// =========================================
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: NativeInteropPlugin
|
||||
|
||||
configurations {
|
||||
cli_bc.extendsFrom compile
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-runtime:$kotlin_version"
|
||||
// We need this configuration to test the helpers.
|
||||
cli_bc jar.outputs.files
|
||||
cli_bc project(path: ':backend.native', configuration: 'cli_bc')
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
testOutputLocal {
|
||||
output.dir(rootProject.file("${findProject(":backend.native:tests").testOutputRoot}/tools/helpers"))
|
||||
}
|
||||
}
|
||||
|
||||
def testDependencies = rootProject.file('dist/dependencies')
|
||||
|
||||
void prepareDependenciesDir(File testDependencies) {
|
||||
project.delete testDependencies
|
||||
testDependencies.mkdirs()
|
||||
// Delete all sysroots from the dependencies cache to tests their downloading.
|
||||
project.delete(project.fileTree("${System.getProperty("user.home")}/.konan/cache/") {
|
||||
include "*sysroot*.tar.gz"
|
||||
})
|
||||
}
|
||||
|
||||
kotlinNativeInterop {
|
||||
sysstat {
|
||||
pkg 'sysstat'
|
||||
headers 'sys/stat.h'
|
||||
flavor 'native'
|
||||
}
|
||||
}
|
||||
|
||||
project.convention.plugins.remoteExec = new org.jetbrains.kotlin.ExecRemote(project)
|
||||
|
||||
task testInteropHelper(type: RunInteropKonanTest) {
|
||||
dependsOn jar
|
||||
dependsOn ':dist'
|
||||
|
||||
dependenciesDir = testDependencies
|
||||
goldValue = "0\n0\n"
|
||||
source = "testData/interop.kt"
|
||||
interop = 'sysstat'
|
||||
|
||||
doFirst {
|
||||
prepareDependenciesDir(testDependencies)
|
||||
project.delete(project.file(buildExePath()).parent)
|
||||
}
|
||||
//Interop gradle plugin doesn't save its work log so we cannot use it to check if dependencies were downloaded or not.
|
||||
}
|
||||
|
||||
task testCompilerHelper(type: RunKonanTest) {
|
||||
dependsOn jar
|
||||
dependsOn ':dist'
|
||||
|
||||
dependenciesDir = testDependencies
|
||||
source = "testData/main.kt"
|
||||
|
||||
doFirst {
|
||||
prepareDependenciesDir(testDependencies)
|
||||
project.delete(project.file(buildExePath()).parent)
|
||||
}
|
||||
|
||||
doLast {
|
||||
if (!file("${buildExePath()}.compilation.log").text.contains("Extract dependency") ||
|
||||
!file("${buildExePath()}.compilation.log").text.contains("Download dependency")) {
|
||||
throw new TestFailedException("Compilation log contains no Extract/Download messages")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple test for parallel compiler execution
|
||||
task testParallel(type: DefaultTask) {
|
||||
dependsOn jar
|
||||
dependsOn ':dist'
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
task("runParallel$i", type: RunKonanTest) {
|
||||
dependenciesDir = testDependencies
|
||||
source = "testData/main.kt"
|
||||
}
|
||||
}
|
||||
|
||||
doFirst {
|
||||
prepareDependenciesDir(testDependencies)
|
||||
}
|
||||
|
||||
doLast {
|
||||
List<Thread> threads = new ArrayList<>()
|
||||
def downloadCnt = new AtomicInteger(0)
|
||||
def extractCnt = new AtomicInteger(0)
|
||||
tasks.withType(RunKonanTest).matching { it.name.startsWith("runParallel") }.each { task ->
|
||||
threads.add(Thread.start {
|
||||
task.executeTest()
|
||||
// The helper prints messages when it is downloading.
|
||||
// We check that there is only one downloading using compilation logs.
|
||||
if (file("${task.buildExePath()}.compilation.log").text.contains("Extract dependency")) {
|
||||
extractCnt.incrementAndGet()
|
||||
}
|
||||
if (file("${task.buildExePath()}.compilation.log").text.contains("Download dependency")) {
|
||||
downloadCnt.incrementAndGet()
|
||||
}
|
||||
})
|
||||
}
|
||||
threads.each { it.join() }
|
||||
if (downloadCnt.intValue() != 1 || extractCnt.intValue() != 1) {
|
||||
throw new TestFailedException("Actual downloads: ${downloadCnt.intValue()}, expected: 1\n" +
|
||||
"Actial extractions: ${extractCnt.intValue()}, expected: 1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task testHelpers {
|
||||
dependsOn testInteropHelper
|
||||
dependsOn testCompilerHelper
|
||||
dependsOn testParallel
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
import java.io.*
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
// TODO: Try to use some dependency management system (Ivy?)
|
||||
/**
|
||||
* Inspects [dependencies] and downloads all the missing ones into [dependenciesDirectory] from [dependenciesUrl].
|
||||
* If [airplaneMode] is true will throw a RuntimeException instead of downloading.
|
||||
*/
|
||||
class DependencyDownloader(dependenciesRoot: File,
|
||||
val dependenciesUrl: String,
|
||||
val dependencies: List<String>,
|
||||
val airplaneMode: Boolean = false,
|
||||
val maxAttempts: Int = DEFAULT_MAX_ATTEMPTS,
|
||||
val attemptPauseMs: Long = DEFAULT_ATTEMPT_PAUSE_MS) {
|
||||
|
||||
val dependenciesDirectory = dependenciesRoot.apply { mkdirs() }
|
||||
val cacheDirectory = System.getProperty("user.home")?.let {
|
||||
File("$it/.konan/cache").apply { mkdirs() }
|
||||
} ?: dependenciesRoot
|
||||
|
||||
val lockFile = File(cacheDirectory, ".lock").apply { if (!exists()) createNewFile() }
|
||||
|
||||
var isInfoShown = false
|
||||
|
||||
class DependencyFile(directory: File, fileName: String) {
|
||||
val file = File(directory, fileName).apply { createNewFile() }
|
||||
private val dependencies = file.readLines().toMutableSet()
|
||||
|
||||
fun contains(dependency: String) = dependencies.contains(dependency)
|
||||
fun add(dependency: String) = dependencies.add(dependency)
|
||||
fun addWithSave(dependency: String) {
|
||||
add(dependency)
|
||||
save()
|
||||
}
|
||||
|
||||
fun save() {
|
||||
val writer = file.writer()
|
||||
writer.use {
|
||||
dependencies.forEach {
|
||||
writer.write(it)
|
||||
writer.write("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val useZip = System.getProperty("os.name").startsWith("Windows")
|
||||
|
||||
private val archiveExtension = if (useZip) {
|
||||
"zip"
|
||||
} else {
|
||||
"tar.gz"
|
||||
}
|
||||
|
||||
private fun processDependency(dependency: String) {
|
||||
val depDir = File(dependenciesDirectory, dependency)
|
||||
val depName = depDir.name
|
||||
|
||||
val extractedDependencies = DependencyFile(dependenciesDirectory, ".extracted")
|
||||
if (extractedDependencies.contains(depName) &&
|
||||
depDir.exists() &&
|
||||
depDir.isDirectory &&
|
||||
depDir.list().isNotEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isInfoShown) {
|
||||
println("Downloading native dependencies (LLVM, sysroot etc). This is a one-time action performed only on the first run of the compiler.")
|
||||
isInfoShown = true
|
||||
}
|
||||
|
||||
val archive = File(cacheDirectory.canonicalPath, "$depName.$archiveExtension")
|
||||
if (!archive.exists()) {
|
||||
if (!airplaneMode) {
|
||||
var attempt = 0
|
||||
while(true) {
|
||||
try {
|
||||
download(depName, archive)
|
||||
break
|
||||
} catch (e: IOException) {
|
||||
if (attempt < maxAttempts) {
|
||||
attempt++
|
||||
val pauseTime = attempt * attemptPauseMs
|
||||
println("Downloading error: ${e.message}.\n" +
|
||||
"Waiting ${pauseTime.toDouble() / 1000} sec and trying again (attempt: $attempt/$maxAttempts)")
|
||||
Thread.sleep(pauseTime)
|
||||
} else { throw e }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw RuntimeException("""
|
||||
Cannot find a dependency locally: $dependency.
|
||||
Set `airplaneMode = false` in konan.properties to download it.
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
extract(archive, dependenciesDirectory)
|
||||
extractedDependencies.addWithSave(depName)
|
||||
}
|
||||
|
||||
private fun extract(archive: File, target: File) {
|
||||
if (useZip) {
|
||||
archive.toPath().unzipTo(target.toPath())
|
||||
} else {
|
||||
extractTarGz(archive, target)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractTarGz(tarGz: File, target: File) {
|
||||
println("Extract dependency: ${tarGz.canonicalPath} in ${target.canonicalPath}")
|
||||
val tarProcess = ProcessBuilder().apply {
|
||||
command("tar", "-xzf", "${tarGz.canonicalPath}")
|
||||
directory(target)
|
||||
}.start()
|
||||
tarProcess.waitFor()
|
||||
if (tarProcess.exitValue() != 0) {
|
||||
throw RuntimeException("Cannot extract archive with dependency: ${tarGz.canonicalPath}")
|
||||
}
|
||||
}
|
||||
|
||||
private val Long.humanReadable: String
|
||||
get() {
|
||||
if (this < 0) {
|
||||
return "-"
|
||||
}
|
||||
if (this < 1024) {
|
||||
return "$this bytes"
|
||||
}
|
||||
val exp = (Math.log(this.toDouble()) / Math.log(1024.0)).toInt()
|
||||
val prefix = "kMGTPE"[exp-1]
|
||||
return "%.1f %siB".format(this / Math.pow(1024.0, exp.toDouble()), prefix)
|
||||
}
|
||||
|
||||
private fun updateProgressMsg(url: String, currentBytes: Long, totalBytes: Long) {
|
||||
print("\rDownload dependency: $url (${currentBytes.humanReadable}/${totalBytes.humanReadable}). ")
|
||||
}
|
||||
|
||||
private fun download(dependencyName: String, outputFile: File) {
|
||||
val tmpFile = File("${outputFile.canonicalPath}.part")
|
||||
val url = URL("$dependenciesUrl/$dependencyName.$archiveExtension")
|
||||
val connection = url.openConnection()
|
||||
val totalBytes = connection.contentLengthLong
|
||||
|
||||
var currentBytes = 0L
|
||||
var done = false
|
||||
var downloadError: Throwable? = null
|
||||
|
||||
thread {
|
||||
try {
|
||||
url.openStream().use { from ->
|
||||
FileOutputStream(tmpFile, false).use { to ->
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var read = from.read(buffer)
|
||||
while (read != -1) {
|
||||
to.write(buffer, 0, read)
|
||||
currentBytes += read
|
||||
read = from.read(buffer)
|
||||
}
|
||||
if (currentBytes != totalBytes) {
|
||||
throw EOFException("The stream closed before end of downloading.")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
downloadError = e
|
||||
}
|
||||
done = true
|
||||
}
|
||||
|
||||
// TODO: Improve console logging
|
||||
while (!done) {
|
||||
Thread.sleep(1000) // We can use condition variable here.
|
||||
updateProgressMsg(url.toString(), currentBytes, totalBytes)
|
||||
}
|
||||
println("Done.")
|
||||
if (downloadError != null) {
|
||||
tmpFile.delete()
|
||||
throw IOException("Cannot download dependency: $url", downloadError)
|
||||
}
|
||||
Files.move(
|
||||
tmpFile.toPath(),
|
||||
outputFile.toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
|
||||
// stdlib `use` function adapted for AutoCloseable.
|
||||
private inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
|
||||
var closed = false
|
||||
try {
|
||||
return block(this)
|
||||
} catch (e: Exception) {
|
||||
closed = true
|
||||
try {
|
||||
this?.close()
|
||||
} catch (closeException: Exception) {
|
||||
}
|
||||
throw e
|
||||
} finally {
|
||||
if (!closed) {
|
||||
this?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val lock = ReentrantLock()
|
||||
|
||||
const val DEFAULT_MAX_ATTEMPTS = 10
|
||||
const val DEFAULT_ATTEMPT_PAUSE_MS = 3000L
|
||||
}
|
||||
|
||||
fun run() = lock.withLock {
|
||||
RandomAccessFile(lockFile, "rw").channel.lock().use {
|
||||
dependencies.forEach {
|
||||
processDependency(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
import java.net.URI
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
fun Path.unzipTo(directory: Path) {
|
||||
val zipUri = URI.create("jar:" + this.toUri())
|
||||
FileSystems.newFileSystem(zipUri, emptyMap<String, Any?>(), null).use { zipfs ->
|
||||
val zipPath = zipfs.getPath("/")
|
||||
zipPath.recursiveCopyTo(directory)
|
||||
}
|
||||
}
|
||||
|
||||
fun Path.recursiveCopyTo(destPath: Path) {
|
||||
val sourcePath = this
|
||||
Files.walk(sourcePath).forEach { oldPath ->
|
||||
|
||||
val relative = sourcePath.relativize(oldPath)
|
||||
|
||||
// We are copying files between file systems,
|
||||
// so pass the relative path through the Sting.
|
||||
val newPath = destPath.resolve(relative.toString())
|
||||
|
||||
if (Files.isDirectory(oldPath)) {
|
||||
Files.createDirectories(newPath)
|
||||
// TODO: consider copying attributes.
|
||||
} else {
|
||||
Files.copy(oldPath, newPath,
|
||||
StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
// TODO: Add command line keys
|
||||
// Args: dependencies directory, dependencies url, max attempts, attempt pause, dependencies list
|
||||
fun main(args: Array<String>) {
|
||||
if (args.size < 5) {
|
||||
System.exit(1)
|
||||
}
|
||||
val dependenciesDir = File(args[0])
|
||||
val dependenciesUrl = args[1]
|
||||
val maxAttempts = args[2].toInt()
|
||||
val attemptPause = args[3].toLong()
|
||||
val dependencies = List<String>(args.size - 4) { args[4 + it] }
|
||||
DependencyDownloader(dependenciesDir,
|
||||
dependenciesUrl,
|
||||
dependencies,
|
||||
maxAttempts = maxAttempts,
|
||||
attemptPauseMs = attemptPause
|
||||
).run()
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import sysstat.*
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val statBuf = nativeHeap.alloc<statStruct>()
|
||||
val res = stat("/", statBuf.ptr)
|
||||
println(res)
|
||||
println(statBuf.st_uid)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fun main(args: Array<String>) {
|
||||
println(42)
|
||||
}
|
||||
@@ -47,11 +47,8 @@ repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
evaluationDependsOn(':tools:helpers')
|
||||
|
||||
dependencies {
|
||||
compile project(':shared')
|
||||
compile project(':tools:helpers')
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile gradleApi()
|
||||
|
||||
@@ -69,8 +66,6 @@ test {
|
||||
}
|
||||
|
||||
jar {
|
||||
dependsOn(':tools:helpers:jar')
|
||||
from (rootProject.findProject(':tools:helpers').sourceSets.main.output)
|
||||
from (rootProject.findProject(':shared').sourceSets.main.output)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.gradle.plugin
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleScriptException
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.jetbrains.kotlin.konan.DependencyDownloader
|
||||
import org.jetbrains.kotlin.konan.util.DependencyProcessor
|
||||
import java.io.File
|
||||
|
||||
open class KonanCompilerDownloadTask : DefaultTask() {
|
||||
@@ -53,7 +53,7 @@ open class KonanCompilerDownloadTask : DefaultTask() {
|
||||
try {
|
||||
val konanCompiler = project.konanCompilerName()
|
||||
logger.info("Downloading Kotlin/Native compiler from $DOWNLOAD_URL/$konanCompiler into $KONAN_PARENT_DIR")
|
||||
DependencyDownloader(File(KONAN_PARENT_DIR), DOWNLOAD_URL, listOf(konanCompiler)).run()
|
||||
DependencyProcessor(File(KONAN_PARENT_DIR), DOWNLOAD_URL, listOf(konanCompiler)).run()
|
||||
} catch (e: RuntimeException) {
|
||||
throw GradleScriptException("Cannot download Kotlin/Native compiler", e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user