Move everything under kotlin-native folder

I was forced to manually do update the following files, because otherwise
they would be ignored according .gitignore settings. Probably they
should be deleted from repo.

Interop/.idea/compiler.xml
Interop/.idea/gradle.xml
Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_3.xml
Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_3.xml
Interop/.idea/modules.xml
Interop/.idea/modules/Indexer/Indexer.iml
Interop/.idea/modules/Runtime/Runtime.iml
Interop/.idea/modules/StubGenerator/StubGenerator.iml
backend.native/backend.native.iml
backend.native/bc.frontend/bc.frontend.iml
backend.native/cli.bc/cli.bc.iml
backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt
backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt
backend.native/tests/link/lib/foo.kt
backend.native/tests/link/lib/foo2.kt
backend.native/tests/teamcity-test.property
This commit is contained in:
Stanislav Erokhin
2020-10-27 21:00:28 +03:00
parent 91e4162dad
commit f624800b84
2830 changed files with 0 additions and 0 deletions
@@ -0,0 +1,32 @@
FROM openjdk:8u171-jdk-stretch as builder
WORKDIR /opt
ENV kotlin_native_ver "0.7.1"
ENV kotlin_native_home "/opt/kotlin-native-linux-$kotlin_native_ver"
RUN wget "https://github.com/JetBrains/kotlin-native/releases/download/v$kotlin_native_ver/kotlin-native-linux-$kotlin_native_ver.tar.gz" \
&& tar -xzf kotlin-native-linux-$kotlin_native_ver.tar.gz && rm kotlin-native-linux-$kotlin_native_ver.tar.gz \
&& apt-get -qy update && apt-get install libcurl4-openssl-dev \
&& mkdir -p /app/src/main/kotlin/org/example/weather_func \
&& mkdir -p /app/lib/cJSON-1.7.7/include/cjson && mkdir -p /app/lib/cJSON-1.7.7/lib/x86_64-linux-gnu \
&& mkdir -p /app/gradle/wrapper
WORKDIR /app
COPY gradle/wrapper/gradle-wrapper.properties gradle/wrapper/gradle-wrapper.jar /app/gradle/wrapper/
COPY gradlew openweathermap_key.txt /app/
COPY .konan/ /root/.konan
COPY *.def *.kts /app/
COPY src/ /app/src
COPY lib/cJSON-1.7.7/include/cjson/cJSON.h /app/lib/cJSON-1.7.7/include/cJSON.h
COPY lib/cJSON-1.7.7/lib/x86_64-linux-gnu/libcjson.a /app/lib/cJSON-1.7.7/lib/libcjson.a
RUN ./gradlew build && cp build/konan/bin/linux_x64/weather.kexe weather
FROM debian:stretch
ADD https://github.com/openfaas/faas/releases/download/0.8.2/fwatchdog /usr/bin
RUN apt-get update && apt-get -qy install libcurl4-openssl-dev \
&& chmod +x /usr/bin/fwatchdog && mkdir -p /app
WORKDIR /app
COPY --from=builder /app/openweathermap_key.txt .
COPY --from=builder /app/weather .
RUN chmod +x weather
ENV fprocess "./weather"
HEALTHCHECK --interval=2s CMD [ -e /tmp/.lock ] || exit 1
CMD ["fwatchdog"]
@@ -0,0 +1,24 @@
group = "org.example"
version = "0.1-SNAPSHOT"
plugins {
id("konan")
}
konanArtifacts {
interop("curl") {
defFile("curl.def")
}
interop("cjson") {
defFile("cjson.def")
}
program("weather") {
entryPoint("org.example.weather_func.main")
libraries {
artifact("cjson")
artifact("curl")
}
}
}
@@ -0,0 +1,6 @@
package = cjson
headers = cJSON.h
compilerOpts = -std=c89
compilerOpts.linux = -I/app/lib/cJSON-1.7.7/include
staticLibraries = libcjson.a
libraryPaths = /app/lib/cJSON-1.7.7/lib
@@ -0,0 +1,5 @@
package = curl
headers = curl.h
linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu -lcurl
compilerOpts = -std=c89
compilerOpts.linux = -I/usr/include/x86_64-linux-gnu/curl
@@ -0,0 +1,20 @@
rootProject.name = "weather-function"
pluginManagement {
repositories {
gradlePluginPortal()
jcenter()
maven("https://dl.bintray.com/jetbrains/kotlin-native-dependencies")
}
// This way we can map plugin to standard maven artifact
// for maven repositories without plugin descriptor
resolutionStrategy {
eachPlugin {
if (requested.id.id == "konan") {
val kotlinNativeVer = "0.7.1"
useModule("org.jetbrains.kotlin:kotlin-native-gradle-plugin:$kotlinNativeVer")
}
}
}
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2018 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.example.weather_func
/** Models the current weather for a location. */
internal data class Weather(
val placeName: String,
val countryCode: String,
val windSpeed: Double = 0.0,
val windDegrees: Int = 0,
val temp: Int,
val minTemp: Int,
val maxTemp: Int,
val humidity: Int,
val conditions: Array<Pair<String, String>>
)
@@ -0,0 +1,94 @@
/*
* Copyright 2010-2018 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.example.weather_func
import org.example.weather_func.Event
import platform.posix.size_t
import curl.curl_easy_setopt
import curl.CURLOPT_URL
import curl.CURLOPT_HEADERFUNCTION
import curl.CURLOPT_HEADERDATA
import curl.CURLOPT_WRITEFUNCTION
import curl.CURLOPT_WRITEDATA
import curl.curl_easy_cleanup
import curl.curl_easy_init
import curl.CURLE_OK
import curl.curl_easy_strerror
import curl.curl_easy_perform
import kotlinx.cinterop.staticCFunction
import kotlinx.cinterop.COpaquePointer
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.StableRef
import kotlinx.cinterop.asStableRef
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.readBytes
/**
* Provides basic HTTP client functionality through the libCurl library.
*/
internal class CUrl(val url: String) {
private val stableRef = StableRef.create(this)
private val curlObj = curl_easy_init()
val header = Event<String>()
val body = Event<String>()
init {
val header = staticCFunction(::headerCallback)
val writeData = staticCFunction(::writeCallback)
// Setup Curl.
curl_easy_setopt(curlObj, CURLOPT_URL, url)
curl_easy_setopt(curlObj, CURLOPT_HEADERFUNCTION, header)
curl_easy_setopt(curlObj, CURLOPT_HEADERDATA, stableRef.asCPointer())
curl_easy_setopt(curlObj, CURLOPT_WRITEFUNCTION, writeData)
curl_easy_setopt(curlObj, CURLOPT_WRITEDATA, stableRef.asCPointer())
}
fun fetch() {
// Have Curl do a HTTP/HTTPS request and store the response (status).
val response = curl_easy_perform(curlObj)
val maxChars = 50
// utfCharSize in bytes.
val utfCharSize = 4
// length in bytes.
val length = utfCharSize * maxChars
// Print the error message if the Curl status code isn't OK (CURLE_OK).
if (response != CURLE_OK) println("Curl HTTP/S request failed: ${curl_easy_strerror(response)?.toKString(length)}")
}
fun close() {
curl_easy_cleanup(curlObj)
stableRef.dispose()
}
}
fun headerCallback(buffer: CPointer<ByteVar>?, size: size_t, totalItems: size_t, userData: COpaquePointer?): size_t {
var responseSize = 0L
if (buffer != null && userData != null) {
val header = buffer.toKString((size * totalItems).toInt()).trim()
val curlRef = userData.asStableRef<CUrl>().get()
curlRef.header(header)
responseSize = size * totalItems
}
return responseSize
}
fun writeCallback(buffer: CPointer<ByteVar>?, size: size_t, totalItems: size_t, userData: COpaquePointer?): size_t {
var responseSize = 0L
if (buffer != null && userData != null) {
val data = buffer.toKString((size * totalItems).toInt()).trim()
val curlRef = userData.asStableRef<CUrl>().get()
curlRef.body(data)
responseSize = size * totalItems
}
return responseSize
}
private fun CPointer<ByteVar>.toKString(length: Int) = readBytes(length).decodeToString()
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 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.example.weather_func
internal typealias EventHandler<T> = (T) -> Unit
/**
* Covers event handling for the program.
*/
internal class Event<T : Any?> {
private var handlers = emptyList<EventHandler<T>>()
fun subscribe(handler: EventHandler<T>) {
handlers += handler
}
fun unsubscribe(handler: EventHandler<T>) {
handlers -= handler
}
operator fun plusAssign(handler: EventHandler<T>) = subscribe(handler)
operator fun minusAssign(handler: EventHandler<T>) = unsubscribe(handler)
operator fun invoke(value: T) {
var exception: Throwable? = null
for (handler in handlers) {
try { handler(value) }
catch (ex: Throwable) { exception = ex }
}
// If the exception isn't null then throw it.
exception?.let { throw it }
}
}
@@ -0,0 +1,167 @@
/*
* Copyright 2010-2018 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.example.weather_func
import cjson.cJSON_CreateObject as createJsonObject
import cjson.cJSON_AddStringToObject as addStringToObject
import cjson.cJSON_AddNumberToObject as addNumberToObject
import cjson.cJSON_AddArrayToObject as addArrayToObject
import cjson.cJSON_AddItemToArray as addItemToArray
import cjson.cJSON_AddItemToObjectCS as addItemToObject
import cjson.cJSON_Delete as deleteObject
import cjson.cJSON_Print as jsonString
import cjson.cJSON_Parse as parseJson
import cjson.cJSON_GetObjectItemCaseSensitive as jsonObjectItem
import cjson.cJSON_IsString as jsonValueIsString
import cjson.cJSON_IsNumber as jsonValueIsNumber
import cjson.cJSON_GetErrorPtr as getErrorPointer
import cjson.cJSON_GetStringValue as jsonStringValue
import cjson.cJSON_GetArraySize as jsonArraySize
import cjson.cJSON_GetArrayItem as jsonArrayItem
import cjson.cJSON
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.toKString
import kotlinx.cinterop.pointed
import kotlin.system.exitProcess
private val trueValue = 1
internal fun createWeatherFromJson(jsonStr: String): Weather {
val rootObj = parseJson(jsonStr)
checkForError()
val result = createWeather(
placeName = jsonObjectItem(rootObj, "name").stringValue(),
countryCode = extractCountryCode(rootObj),
windInfo = extractWindInfo(rootObj),
conditions = extractConditions(rootObj),
tempInfo = extractTempInfo(rootObj),
humidity = extractHumidity(rootObj)
)
if (rootObj != null) deleteObject(rootObj)
return result
}
/**
* Creates a new Weather object.
* @param placeName Name of the place.
* @param countryCode Unique country code.
* @param windInfo A Pair with wind speed as 1st item, and wind degrees as 2nd item.
* @param conditions A Array of Pair. Each Pair has name as 1st item, and desc as 2nd item.
* @param humidity General humidity of the atmosphere.
* @param tempInfo A Triple with temperature as 1st item, min temperature as 2nd item, and max temperature as 3rd item.
* @return A instance of Weather.
*/
private fun createWeather(
placeName: String,
countryCode: String,
windInfo: Pair<Double, Int>,
conditions: Array<Pair<String, String>>,
humidity: Int,
tempInfo: Triple<Int, Int, Int>
) = Weather(
placeName = placeName,
countryCode = countryCode,
conditions = conditions,
humidity = humidity,
windSpeed = windInfo.first,
windDegrees = windInfo.second,
temp = tempInfo.first,
minTemp = tempInfo.second,
maxTemp = tempInfo.third
)
private fun extractTempInfo(rootObj: CPointer<cJSON>?): Triple<Int, Int, Int> {
val mainObj = jsonObjectItem(rootObj, "main")
val temp = jsonObjectItem(mainObj, "temp").intValue()
val minTemp = jsonObjectItem(mainObj, "temp_min").intValue()
val maxTemp = jsonObjectItem(mainObj, "temp_max").intValue()
return Triple(temp, minTemp, maxTemp)
}
private fun extractHumidity(rootObj: CPointer<cJSON>?): Int {
val mainObj = jsonObjectItem(rootObj, "main")
return jsonObjectItem(mainObj, "humidity").intValue()
}
private fun extractConditions(rootObj: CPointer<cJSON>?): Array<Pair<String, String>> {
val tmp = mutableListOf<Pair<String, String>>()
val weatherObj = jsonObjectItem(rootObj, "weather")
for (pos in 0..(jsonArraySize(weatherObj) - 1)) {
val item = jsonArrayItem(weatherObj, pos)
val name = jsonObjectItem(item, "main").stringValue()
val desc = jsonObjectItem(item, "description").stringValue()
tmp += (name to desc)
}
return tmp.toTypedArray()
}
private fun extractWindInfo(rootObj: CPointer<cJSON>?): Pair<Double, Int> {
val windObj = jsonObjectItem(rootObj, "wind")
val windSpeed = jsonObjectItem(windObj, "speed").doubleValue()
val windDegrees = jsonObjectItem(windObj, "deg").intValue()
return (windSpeed to windDegrees)
}
private fun extractCountryCode(rootObj: CPointer<cJSON>?): String {
val sys = jsonObjectItem(rootObj, "sys")
return jsonObjectItem(sys, "country").stringValue()
}
internal fun weatherToJsonString(weather: Weather) : String {
val rootObj = createJsonObject()
addStringToObject(rootObj, "placeName", weather.placeName)
addStringToObject(rootObj, "countryCode", weather.countryCode)
addNumberToObject(rootObj, "humidity", weather.humidity.toDouble())
addTempInfoArray(rootObj, temp = weather.temp, minTemp = weather.minTemp, maxTemp = weather.maxTemp)
addConditionsArray(rootObj, weather.conditions)
val result = jsonString(rootObj)?.toKString() ?: ""
deleteObject(rootObj)
return result
}
private fun addTempInfoArray(rootObj: CPointer<cJSON>?, temp: Int, minTemp: Int, maxTemp: Int) {
val tmpObj = createJsonObject()
addNumberToObject(tmpObj, "temp", temp.toDouble())
addNumberToObject(tmpObj, "minTemp", minTemp.toDouble())
addNumberToObject(tmpObj, "maxTemp", maxTemp.toDouble())
addItemToObject(rootObj, "tempInfo", tmpObj)
}
private fun addConditionsArray(rootObj: CPointer<cJSON>?, conditions: Array<Pair<String, String>>) {
val tmpArr = addArrayToObject(rootObj, "conditions")
conditions.forEach { (name, desc) ->
val tmpObj = createJsonObject()
addStringToObject(tmpObj, "name", name)
addStringToObject(tmpObj, "desc", desc)
addItemToArray(tmpArr, tmpObj)
}
}
private fun checkForError() {
val errorMsg = getErrorPointer()?.toKString() ?: ""
if (errorMsg.isNotEmpty()) {
println("JSON error before: $errorMsg\n")
exitProcess(-1)
}
}
private fun CPointer<cJSON>?.intValue() = this?.pointed?.valueint ?: 0
private fun CPointer<cJSON>?.doubleValue() = this?.pointed?.valuedouble ?: 0.0
private fun CPointer<cJSON>?.stringValue() = jsonStringValue(this)?.toKString() ?: ""
@@ -0,0 +1,123 @@
/*
* Copyright 2010-2018 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.example.weather_func
import platform.posix.*
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toKString
import kotlinx.cinterop.refTo
import kotlin.system.exitProcess
private val API_KEY by lazy { fetchApiKey() }
fun main(args: Array<String>) {
val input = readLine()
val location = fetchLocationArg(input)
val jsonFile = fetchJsonFileArg(input)
if (location.isNotEmpty()) {
printFromWeatherService(location)
} else if (jsonFile.isNotEmpty()) {
checkFile(jsonFile)
printJsonFile(jsonFile)
} else {
handleEmptyInput()
}
println("Exiting...")
}
private fun handleEmptyInput() {
println(
"""
| Weather - A OpenFaaS Serverless Function that outputs weather information.
| Usage examples (pass one of the following as input to the function):
| * Location (uses the Open Weather Map service), eg:
| -l="christchurch,nz"
| * JSON File, eg: -f="weather.json"
""".trimMargin()
)
exitProcess(0)
}
private fun checkFile(file: String) {
val error = -1
if (access(file, F_OK) == error) {
println("File $file doesn't exist!")
exitProcess(error)
}
}
private fun fetchJson(jsonFile: String): String {
var result = ""
// Open the file using the fopen function and store the file handle.
val file = fopen(jsonFile, "r")
fseek(file, 0, SEEK_END)
val fileSize = ftell(file)
fseek(file, 0, SEEK_SET)
memScoped {
val buffer = allocArray<ByteVar>(fileSize)
// Read the entire file and store the contents into the buffer.
fread(buffer, fileSize, 1, file)
result = buffer.toKString()
}
// Close the file.
fclose(file)
return result
}
private fun printJsonFile(jsonFile: String) {
println("Printing from JSON file ($jsonFile)...")
val weather = createWeatherFromJson(fetchJson(jsonFile))
println("Weather Object:\n$weather")
println("Weather JSON:\n${weatherToJsonString(weather)}")
}
private fun printFromWeatherService(location: String) {
println("Fetching weather information (for $location)...")
val curl = CUrl(createUrl(location)).apply {
header += { if(it.startsWith("HTTP")) println("Response Status: $it") }
body += { data ->
val weather = createWeatherFromJson(data)
println("Weather information:\n${weatherToJsonString(weather)}")
}
}
curl.fetch()
curl.close()
}
private fun fetchJsonFileArg(input: String?): String {
val flag = "-f"
return if (input != null && input.startsWith("$flag=")) input.replace("$flag=", "").replace("\"", "")
else ""
}
private fun fetchLocationArg(input: String?): String {
val flag = "-l"
return if (input != null && input.startsWith("$flag=")) input.replace("$flag=", "").replace("\"", "")
else ""
}
private fun createUrl(location: String): String {
val baseUrl = "http://api.openweathermap.org/data/2.5/weather"
return "$baseUrl?q=$location&units=metric&appid=$API_KEY"
}
private fun fetchApiKey(): String {
var result = ""
val maxChars = 50
// utfCharSize in bytes.
val utfCharSize = 4
// Open the file using the fopen function and store the file handle.
val file = fopen("openweathermap_key.txt", "r")
val buffer = ByteArray(utfCharSize * maxChars)
if (file != null) result = fgets(buffer.refTo(0), buffer.size, file)?.toKString()?.trim() ?: ""
// Close the file.
fclose(file)
return result
}