Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LinuxLocalTimeFormatter, LinuxTimeZoneInfoProvider #207

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import ru.pixnews.wasm.sqlite.driver.test.base.tests.AbstractTimeFunctionsTest
import ru.pixnews.wasm.sqlite.test.utils.TempFolder
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Ignore
import kotlin.test.Test

class ChasmTimeFunctionsTest : AbstractTimeFunctionsTest<WasmSQLiteDriver<*>>(
driverCreator = ChasmSqliteDriverFactory,
Expand All @@ -30,10 +28,4 @@ class ChasmTimeFunctionsTest : AbstractTimeFunctionsTest<WasmSQLiteDriver<*>>(
}

override fun fileInTempDir(databaseName: String): String = tempDir.resolve(databaseName)

@Test
@Ignore // TODO
override fun localtime_modifier_should_work() {
super.localtime_modifier_should_work()
}
}
47 changes: 47 additions & 0 deletions sqlite-tests/sqlite-test-utils/src/linuxMain/kotlin/TimeZoneExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file
* for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
* SPDX-License-Identifier: Apache-2.0
*/

package ru.pixnews.wasm.sqlite.test.utils

import kotlinx.cinterop.toKStringFromUtf8
import platform.posix.errno
import platform.posix.getenv
import platform.posix.setenv
import platform.posix.tzset
import platform.posix.unsetenv

public fun <R : Any> withTimeZone(
timeZone: String,
block: () -> R,
) {
val oldTz = getenv("TZ")?.toKStringFromUtf8()
setEnvOrThrow("TZ", timeZone)
tzset()
try {
block()
} finally {
if (oldTz == null) {
val unsetEnvResult = unsetenv("TZ")
if (unsetEnvResult < 0) {
error("Can not unset TZ. Errno: $errno")
}
} else {
setEnvOrThrow("TZ", oldTz)
}
tzset()
}
}

private fun setEnvOrThrow(
name: String,
value: String,
replace: Boolean = true,
) {
val setEnvResult = setenv(name, value, if (replace) 1 else 0)
if (setEnvResult < 0) {
error("Can not set $name to `$value`. Errno: $errno")
}
}
12 changes: 6 additions & 6 deletions wasi-emscripten-host/api/wasi-emscripten-host.api
Original file line number Diff line number Diff line change
Expand Up @@ -691,10 +691,10 @@ public final class ru/pixnews/wasm/sqlite/open/helper/host/include/StructTimespe
}

public final class ru/pixnews/wasm/sqlite/open/helper/host/include/StructTm {
public fun <init> (IIIIIIIIIILjava/lang/String;)V
public synthetic fun <init> (IIIIIIIIIILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (IIIIIIIIIJLjava/lang/String;)V
public synthetic fun <init> (IIIIIIIIIJLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()I
public final fun component10 ()I
public final fun component10 ()J
public final fun component11 ()Ljava/lang/String;
public final fun component2 ()I
public final fun component3 ()I
Expand All @@ -704,10 +704,10 @@ public final class ru/pixnews/wasm/sqlite/open/helper/host/include/StructTm {
public final fun component7 ()I
public final fun component8 ()I
public final fun component9 ()I
public final fun copy (IIIIIIIIIILjava/lang/String;)Lru/pixnews/wasm/sqlite/open/helper/host/include/StructTm;
public static synthetic fun copy$default (Lru/pixnews/wasm/sqlite/open/helper/host/include/StructTm;IIIIIIIIIILjava/lang/String;ILjava/lang/Object;)Lru/pixnews/wasm/sqlite/open/helper/host/include/StructTm;
public final fun copy (IIIIIIIIIJLjava/lang/String;)Lru/pixnews/wasm/sqlite/open/helper/host/include/StructTm;
public static synthetic fun copy$default (Lru/pixnews/wasm/sqlite/open/helper/host/include/StructTm;IIIIIIIIIJLjava/lang/String;ILjava/lang/Object;)Lru/pixnews/wasm/sqlite/open/helper/host/include/StructTm;
public fun equals (Ljava/lang/Object;)Z
public final fun getTm_gmtoff ()I
public final fun getTm_gmtoff ()J
public final fun getTm_hour ()I
public final fun getTm_isdst ()I
public final fun getTm_mday ()I
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public data class StructTm(
val tm_wday: Int,
val tm_yday: Int,
val tm_isdst: Int,
val tm_gmtoff: Int,
val tm_gmtoff: Long,
val tm_zone: String? = null,
) {
val isDstFlag: IsDstFlag = when {
Expand Down Expand Up @@ -82,7 +82,7 @@ public fun StructTm.packTo(sink: Sink): Unit = sink.run {
writeIntLe(tm_wday) // 24
writeIntLe(tm_yday) // 28
writeIntLe(tm_isdst) // 32
writeIntLe(tm_gmtoff) // 36
writeIntLe(tm_gmtoff.toInt()) // 36
}

public fun StructTm.pack(): Buffer = Buffer().also {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file
* for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
* SPDX-License-Identifier: Apache-2.0
*/

package ru.pixnews.wasm.sqlite.open.helper.host.internal

import ru.pixnews.wasm.sqlite.open.helper.host.EmbedderHost

internal object EmptyCommandArgsProvider : EmbedderHost.CommandArgsProvider {
override fun getCommandArgs(): List<String> = emptyList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class JvmLocalTimeFormatter(
localTimeZoneProvider(),
)
val zone = date.zone
@Suppress("COMPLEX_EXPRESSION")
return StructTm(
tm_sec = date.second,
tm_min = date.minute,
Expand All @@ -38,7 +39,7 @@ public class JvmLocalTimeFormatter(
} else {
StructTm.IsDstFlag.NOT_IN_EFFECT
}.asTmIsdstValue(),
tm_gmtoff = zone.rules.getOffset(date.toInstant()).totalSeconds,
tm_gmtoff = zone.rules.getOffset(date.toInstant()).totalSeconds.toLong(),
tm_zone = zone.id,
)
}
Expand Down
12 changes: 6 additions & 6 deletions wasi-emscripten-host/src/linuxMain/kotlin/EmbedderHost.linux.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ import ru.pixnews.wasm.sqlite.open.helper.host.ext.DefaultFileSystem
import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.LinuxFileSystem
import ru.pixnews.wasm.sqlite.open.helper.host.internal.CommonClock
import ru.pixnews.wasm.sqlite.open.helper.host.internal.CommonMonotonicClock
import ru.pixnews.wasm.sqlite.open.helper.host.internal.EmptyCommandArgsProvider
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxEmbedderHost
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxEmbedderHost.NativeCommandArgsProvider
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxEmbedderHost.NativeSystemEnvProvider
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxEntropySource
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxLocalTimeFormatter
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxSystemEnvProvider
import ru.pixnews.wasm.sqlite.open.helper.host.linux.LinuxTimeZoneInfoProvider

internal actual fun createDefaultEmbedderHost(builder: Builder): EmbedderHost = LinuxEmbedderHost(
rootLogger = builder.rootLogger,
systemEnvProvider = builder.systemEnvProvider ?: NativeSystemEnvProvider,
commandArgsProvider = builder.commandArgsProvider ?: NativeCommandArgsProvider,
systemEnvProvider = builder.systemEnvProvider ?: LinuxSystemEnvProvider,
commandArgsProvider = builder.commandArgsProvider ?: EmptyCommandArgsProvider,
fileSystem = builder.fileSystem ?: DefaultFileSystem(LinuxFileSystem, builder.rootLogger.withTag("FSlnx")),
monotonicClock = builder.monotonicClock ?: CommonMonotonicClock(),
clock = builder.clock ?: CommonClock(),
localTimeFormatter = builder.localTimeFormatter ?: LinuxLocalTimeFormatter(),
timeZoneInfo = builder.timeZoneInfo ?: LinuxTimeZoneInfoProvider(),
localTimeFormatter = builder.localTimeFormatter ?: LinuxLocalTimeFormatter,
timeZoneInfo = builder.timeZoneInfo ?: LinuxTimeZoneInfoProvider,
entropySource = builder.entropySource ?: LinuxEntropySource(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,16 @@ import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.FileSystem
import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.LinuxFileSystem
import ru.pixnews.wasm.sqlite.open.helper.host.internal.CommonClock
import ru.pixnews.wasm.sqlite.open.helper.host.internal.CommonMonotonicClock
import ru.pixnews.wasm.sqlite.open.helper.host.internal.EmptyCommandArgsProvider

public class LinuxEmbedderHost(
override val rootLogger: Logger,
override val systemEnvProvider: SystemEnvProvider = NativeSystemEnvProvider,
override val commandArgsProvider: CommandArgsProvider = NativeCommandArgsProvider,
override val systemEnvProvider: SystemEnvProvider = LinuxSystemEnvProvider,
override val commandArgsProvider: CommandArgsProvider = EmptyCommandArgsProvider,
override val fileSystem: FileSystem = DefaultFileSystem(LinuxFileSystem, rootLogger.withTag("FSlnx")),
override val monotonicClock: MonotonicClock = CommonMonotonicClock(),
override val clock: Clock = CommonClock(),
override val localTimeFormatter: LocalTimeFormatter = LinuxLocalTimeFormatter(),
override val timeZoneInfo: TimeZoneInfoProvider = LinuxTimeZoneInfoProvider(),
override val localTimeFormatter: LocalTimeFormatter = LinuxLocalTimeFormatter,
override val timeZoneInfo: TimeZoneInfoProvider = LinuxTimeZoneInfoProvider,
override val entropySource: EntropySource = LinuxEntropySource(),
) : EmbedderHost {
internal object NativeSystemEnvProvider : SystemEnvProvider {
override fun getSystemEnv(): Map<String, String> = emptyMap() // TODO:
}

internal object NativeCommandArgsProvider : CommandArgsProvider {
override fun getCommandArgs(): List<String> = emptyList()
}
}
) : EmbedderHost
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,41 @@

package ru.pixnews.wasm.sqlite.open.helper.host.linux

import kotlinx.cinterop.CPointer
import kotlinx.cinterop.LongVarOf
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.pointed
import kotlinx.cinterop.ptr
import kotlinx.cinterop.toKStringFromUtf8
import kotlinx.cinterop.value
import platform.posix.localtime_r
import platform.posix.time_t
import platform.posix.tm
import ru.pixnews.wasm.sqlite.open.helper.host.EmbedderHost.LocalTimeFormatter
import ru.pixnews.wasm.sqlite.open.helper.host.include.StructTm

internal class LinuxLocalTimeFormatter : LocalTimeFormatter {
override fun format(epochSeconds: Long): StructTm {
TODO("Not yet implemented")
internal object LinuxLocalTimeFormatter : LocalTimeFormatter {
override fun format(epochSeconds: Long): StructTm = memScoped {
val epochRef: LongVarOf<time_t> = alloc<LongVarOf<time_t>>().apply {
value = epochSeconds
}
val resultBuf: tm = alloc()

val result: CPointer<tm> = localtime_r(epochRef.ptr, resultBuf.ptr) ?: error("localtime_r() failed")
val tm = result.pointed
StructTm(
tm_sec = tm.tm_sec,
tm_min = tm.tm_min,
tm_hour = tm.tm_hour,
tm_mday = tm.tm_mday,
tm_mon = tm.tm_mon,
tm_year = tm.tm_year,
tm_wday = tm.tm_wday,
tm_yday = tm.tm_yday,
tm_isdst = tm.tm_isdst,
tm_gmtoff = tm.tm_gmtoff,
tm_zone = tm.tm_zone?.toKStringFromUtf8(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file
* for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
* SPDX-License-Identifier: Apache-2.0
*/

package ru.pixnews.wasm.sqlite.open.helper.host.linux

import kotlinx.cinterop.ByteVarOf
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.CPointerVarOf
import kotlinx.cinterop.get
import kotlinx.cinterop.toKStringFromUtf8
import platform.posix.__environ
import ru.pixnews.wasm.sqlite.open.helper.host.EmbedderHost.SystemEnvProvider
import ru.pixnews.wasm.sqlite.open.helper.host.native.parsePosixEnvironToEnvMap

internal object LinuxSystemEnvProvider : SystemEnvProvider {
override fun getSystemEnv(): Map<String, String> {
val envVariables: MutableList<String> = mutableListOf()
val env: CPointer<CPointerVarOf<CPointer<ByteVarOf<Byte>>>> = __environ ?: return emptyMap()
var index = 0
while (true) {
val current = env[index] ?: break
envVariables += current.toKStringFromUtf8()
index += 1
}
return parsePosixEnvironToEnvMap(envVariables)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@

package ru.pixnews.wasm.sqlite.open.helper.host.linux

import kotlinx.cinterop.get
import kotlinx.cinterop.toKStringFromUtf8
import platform.posix.tzname
import ru.pixnews.wasm.sqlite.open.helper.host.EmbedderHost.TimeZoneInfoProvider
import ru.pixnews.wasm.sqlite.open.helper.host.include.TimeZoneInfo

internal class LinuxTimeZoneInfoProvider : TimeZoneInfoProvider {
internal object LinuxTimeZoneInfoProvider : TimeZoneInfoProvider {
override fun getTimeZoneInfo(): TimeZoneInfo {
error("Not implemented")
return TimeZoneInfo(
timeZone = platform.posix.timezone_,
daylight = platform.posix.daylight,
stdName = tzname[0]?.toKStringFromUtf8() ?: "unk",
dstName = tzname[1]?.toKStringFromUtf8() ?: "unk",
)
}
}
10 changes: 10 additions & 0 deletions wasi-emscripten-host/src/linuxTest/kotlin/Dummy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file
* for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
* SPDX-License-Identifier: Apache-2.0
*/

@file:Suppress("FILE_CONTAINS_ONLY_COMMENTS", "FILE_NO_BLANK_LINE_BETWEEN_BLOCKS")

// Workaround for https://youtrack.jetbrains.com/issue/KTIJ-15797
package ru.pixnews.wasm.sqlite.open.helper.host
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file
* for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
* SPDX-License-Identifier: Apache-2.0
*/

package ru.pixnews.wasm.sqlite.open.helper.host.linux

import assertk.assertThat
import assertk.assertions.isEqualTo
import ru.pixnews.wasm.sqlite.open.helper.host.include.StructTm
import ru.pixnews.wasm.sqlite.test.utils.withTimeZone
import kotlin.test.Test

class LinuxLocalTimeFormatterTest {
@Test
@Suppress("MagicNumber")
fun formatter_should_work() = withTimeZone("Asia/Novosibirsk") {
val tm: StructTm = LinuxLocalTimeFormatter.format(1_724_702_567)
assertThat(tm).isEqualTo(
StructTm(
tm_sec = 47,
tm_min = 2,
tm_hour = 3,
tm_mday = 27,
tm_mon = 7,
tm_year = 124,
tm_wday = 2,
tm_yday = 239,
tm_isdst = 0,
tm_gmtoff = 7 * 60 * 60,
tm_zone = "+07",
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file
* for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
* SPDX-License-Identifier: Apache-2.0
*/

package ru.pixnews.wasm.sqlite.open.helper.host.linux

import assertk.all
import assertk.assertThat
import assertk.assertions.contains
import assertk.assertions.isTrue
import platform.posix.setenv
import platform.posix.unsetenv
import kotlin.test.Test

class LinuxSystemEnvProviderTest {
@Test
fun env_provider_should_return_values() {
val testEnvVarKey = "TESTENVVARKEY"
val testEnvVarValue = " test = value"
setenv(testEnvVarKey, testEnvVarValue, 1)
try {
val env = LinuxSystemEnvProvider.getSystemEnv()
assertThat(env).all {
contains(testEnvVarKey, testEnvVarValue)
transform { it.containsKey("USER") }.isTrue()
}
} finally {
unsetenv(testEnvVarKey)
}
}
}
Loading
Loading