Fix native CLI TCP regression path
This commit is contained in:
parent
aa1b74620e
commit
402b8bb1b3
68
examples/tcp-server.lyng
Normal file
68
examples/tcp-server.lyng
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import lyng.buffer
|
||||||
|
import lyng.io.net
|
||||||
|
|
||||||
|
val host = "127.0.0.1"
|
||||||
|
val port = 8092
|
||||||
|
val N = 5
|
||||||
|
val server = Net.tcpListen(port, host)
|
||||||
|
println("start tcp server at $host:$port")
|
||||||
|
|
||||||
|
fun serveClient(client: TcpSocket) = launch {
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
val data = client.read()
|
||||||
|
if (data == null) break
|
||||||
|
var line = (data as Buffer).decodeUtf8()
|
||||||
|
line = "[" + client.remoteAddress() + "]> " + line
|
||||||
|
println(line)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
println("ERROR [reader]: " + e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serveRequests(server: TcpServer) = launch {
|
||||||
|
val readers = []
|
||||||
|
try {
|
||||||
|
for (i in 0..<5) {
|
||||||
|
val client = server.accept()
|
||||||
|
println("accept new connection: " + client.remoteAddress())
|
||||||
|
readers.add(serveClient(client as TcpSocket))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
println("ERROR [listener]: " + e)
|
||||||
|
} finally {
|
||||||
|
server.close()
|
||||||
|
}
|
||||||
|
for (i in 0..<readers.size) {
|
||||||
|
val reader = readers[i]
|
||||||
|
(reader as Deferred).await()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val srv = serveRequests(server as TcpServer)
|
||||||
|
|
||||||
|
var clients = []
|
||||||
|
for (i in 0..<N) {
|
||||||
|
//delay(500)
|
||||||
|
clients.add(launch {
|
||||||
|
try{
|
||||||
|
val socket = Net.tcpConnect(host, port)
|
||||||
|
socket.writeUtf8("ping1ping2ping3ping4ping5")
|
||||||
|
socket.flush()
|
||||||
|
socket.close()
|
||||||
|
} catch (e) {
|
||||||
|
println("ERROR [client]: " + e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0..<clients.size) {
|
||||||
|
val c = clients[i]
|
||||||
|
(c as Deferred).await()
|
||||||
|
println("client done")
|
||||||
|
}
|
||||||
|
|
||||||
|
srv.await()
|
||||||
|
delay(10000)
|
||||||
|
println("FIN")
|
||||||
@ -18,6 +18,7 @@ slf4j = "2.0.17"
|
|||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
clikt = { module = "com.github.ajalt.clikt:clikt", version.ref = "clikt" }
|
clikt = { module = "com.github.ajalt.clikt:clikt", version.ref = "clikt" }
|
||||||
|
clikt-core = { module = "com.github.ajalt.clikt:clikt-core", version.ref = "clikt" }
|
||||||
clikt-markdown = { module = "com.github.ajalt.clikt:clikt-markdown", version.ref = "clikt" }
|
clikt-markdown = { module = "com.github.ajalt.clikt:clikt-markdown", version.ref = "clikt" }
|
||||||
mordant-core = { module = "com.github.ajalt.mordant:mordant-core", version.ref = "mordant" }
|
mordant-core = { module = "com.github.ajalt.mordant:mordant-core", version.ref = "mordant" }
|
||||||
mordant-jvm-jna = { module = "com.github.ajalt.mordant:mordant-jvm-jna", version.ref = "mordant" }
|
mordant-jvm-jna = { module = "com.github.ajalt.mordant:mordant-jvm-jna", version.ref = "mordant" }
|
||||||
|
|||||||
@ -52,6 +52,12 @@ kotlin {
|
|||||||
linuxX64 {
|
linuxX64 {
|
||||||
binaries {
|
binaries {
|
||||||
executable()
|
executable()
|
||||||
|
all {
|
||||||
|
if (buildType == org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.RELEASE) {
|
||||||
|
debuggable = true
|
||||||
|
optimized = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@ -63,7 +69,7 @@ kotlin {
|
|||||||
// filesystem access into the execution Scope by default.
|
// filesystem access into the execution Scope by default.
|
||||||
implementation(project(":lyngio"))
|
implementation(project(":lyngio"))
|
||||||
implementation(libs.okio)
|
implementation(libs.okio)
|
||||||
implementation(libs.clikt)
|
implementation(libs.clikt.core)
|
||||||
implementation(kotlin("stdlib-common"))
|
implementation(kotlin("stdlib-common"))
|
||||||
// optional support for rendering markdown in help messages
|
// optional support for rendering markdown in help messages
|
||||||
// implementation(libs.clikt.markdown)
|
// implementation(libs.clikt.markdown)
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package net.sergeych
|
package net.sergeych
|
||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CoreCliktCommand
|
||||||
import com.github.ajalt.clikt.core.Context
|
import com.github.ajalt.clikt.core.Context
|
||||||
import com.github.ajalt.clikt.core.main
|
import com.github.ajalt.clikt.core.main
|
||||||
import com.github.ajalt.clikt.core.subcommands
|
import com.github.ajalt.clikt.core.subcommands
|
||||||
@ -43,6 +43,7 @@ import net.sergeych.lyng.io.net.createNetModule
|
|||||||
import net.sergeych.lyng.io.ws.createWsModule
|
import net.sergeych.lyng.io.ws.createWsModule
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.pacman.ImportManager
|
import net.sergeych.lyng.pacman.ImportManager
|
||||||
|
import net.sergeych.lyngio.net.shutdownSystemNetEngine
|
||||||
import net.sergeych.lyngio.console.security.PermitAllConsoleAccessPolicy
|
import net.sergeych.lyngio.console.security.PermitAllConsoleAccessPolicy
|
||||||
import net.sergeych.lyngio.fs.security.PermitAllAccessPolicy
|
import net.sergeych.lyngio.fs.security.PermitAllAccessPolicy
|
||||||
import net.sergeych.lyngio.http.security.PermitAllHttpAccessPolicy
|
import net.sergeych.lyngio.http.security.PermitAllHttpAccessPolicy
|
||||||
@ -70,10 +71,18 @@ data class CommandResult(
|
|||||||
val error: String
|
val error: String
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val baseCliImportManagerDefer = globalDefer {
|
||||||
|
val manager = Script.defaultImportManager.copy().apply {
|
||||||
|
installCliModules(this)
|
||||||
|
}
|
||||||
|
manager.newStdScope()
|
||||||
|
manager
|
||||||
|
}
|
||||||
|
|
||||||
val baseScopeDefer = globalDefer {
|
val baseScopeDefer = globalDefer {
|
||||||
Script.newScope().apply {
|
baseCliImportManagerDefer.await().copy().newStdScope().apply {
|
||||||
installCliBuiltins()
|
installCliBuiltins()
|
||||||
installCliModules(importManager)
|
addConst("ARGV", ObjList(mutableListOf()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,23 +217,33 @@ private fun discoverLocalCliModules(entryFile: Path): List<LocalCliModule> {
|
|||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerLocalCliModules(manager: ImportManager, entryFile: Path) {
|
private fun registerLocalCliModules(manager: ImportManager, modules: List<LocalCliModule>) {
|
||||||
for (module in discoverLocalCliModules(entryFile)) {
|
for (module in modules) {
|
||||||
manager.addPackage(module.packageName) { scope ->
|
manager.addPackage(module.packageName) { scope ->
|
||||||
scope.eval(module.source)
|
scope.eval(module.source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun newCliScope(argv: List<String>, entryFileName: String? = null): Scope {
|
private suspend fun ImportManager.newCliScope(argv: List<String>): Scope =
|
||||||
val manager = baseScopeDefer.await().importManager.copy()
|
newStdScope().apply {
|
||||||
if (entryFileName != null) {
|
|
||||||
registerLocalCliModules(manager, canonicalPath(entryFileName.toPath()))
|
|
||||||
}
|
|
||||||
return manager.newStdScope().apply {
|
|
||||||
installCliBuiltins()
|
installCliBuiltins()
|
||||||
addConst("ARGV", ObjList(argv.map { ObjString(it) }.toMutableList()))
|
addConst("ARGV", ObjList(argv.map { ObjString(it) }.toMutableList()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal suspend fun newCliScope(argv: List<String>, entryFileName: String? = null): Scope {
|
||||||
|
val baseManager = baseCliImportManagerDefer.await()
|
||||||
|
if (entryFileName == null) {
|
||||||
|
return baseManager.newCliScope(argv)
|
||||||
|
}
|
||||||
|
val entryFile = canonicalPath(entryFileName.toPath())
|
||||||
|
val localModules = discoverLocalCliModules(entryFile)
|
||||||
|
if (localModules.isEmpty()) {
|
||||||
|
return baseManager.newCliScope(argv)
|
||||||
|
}
|
||||||
|
val manager = baseManager.copy()
|
||||||
|
registerLocalCliModules(manager, localModules)
|
||||||
|
return manager.newCliScope(argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runMain(args: Array<String>) {
|
fun runMain(args: Array<String>) {
|
||||||
@ -248,7 +267,7 @@ fun runMain(args: Array<String>) {
|
|||||||
.main(args)
|
.main(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Fmt : CliktCommand(name = "fmt") {
|
private class Fmt : CoreCliktCommand(name = "fmt") {
|
||||||
private val checkOnly by option("--check", help = "Check only; print files that would change").flag()
|
private val checkOnly by option("--check", help = "Check only; print files that would change").flag()
|
||||||
private val inPlace by option("-i", "--in-place", help = "Write changes back to files").flag()
|
private val inPlace by option("-i", "--in-place", help = "Write changes back to files").flag()
|
||||||
private val enableSpacing by option("--spacing", help = "Apply spacing normalization").flag()
|
private val enableSpacing by option("--spacing", help = "Apply spacing normalization").flag()
|
||||||
@ -306,7 +325,7 @@ private class Fmt : CliktCommand(name = "fmt") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() {
|
private class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CoreCliktCommand() {
|
||||||
|
|
||||||
override val invokeWithoutSubcommand = true
|
override val invokeWithoutSubcommand = true
|
||||||
override val printHelpOnEmptyArgs = true
|
override val printHelpOnEmptyArgs = true
|
||||||
@ -382,6 +401,7 @@ suspend fun executeSource(source: Source, initialScope: Scope? = null) {
|
|||||||
evalOnCliDispatcher(session, source)
|
evalOnCliDispatcher(session, source)
|
||||||
} finally {
|
} finally {
|
||||||
session.cancelAndJoin()
|
session.cancelAndJoin()
|
||||||
|
shutdownSystemNetEngine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
package net.sergeych
|
||||||
|
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import net.sergeych.lyng.EvalSession
|
||||||
|
import net.sergeych.lyng.Source
|
||||||
|
import net.sergeych.lyng.obj.ObjString
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class CliTcpServerRegressionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun reducedTcpServerExampleRunsWithCopiedCliImportManager() = runBlocking {
|
||||||
|
val cliScope = newCliScope(emptyList())
|
||||||
|
val session = EvalSession(cliScope)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val result = evalOnCliDispatcher(
|
||||||
|
session,
|
||||||
|
Source(
|
||||||
|
"<tcp-server-regression>",
|
||||||
|
"""
|
||||||
|
import lyng.buffer
|
||||||
|
import lyng.io.net
|
||||||
|
|
||||||
|
val host = "127.0.0.1"
|
||||||
|
val server = Net.tcpListen(0, host)
|
||||||
|
val port = server.localAddress().port
|
||||||
|
val accepted = launch {
|
||||||
|
val client = server.accept()
|
||||||
|
val line = (client.read(4) as Buffer).decodeUtf8()
|
||||||
|
client.close()
|
||||||
|
server.close()
|
||||||
|
line
|
||||||
|
}
|
||||||
|
|
||||||
|
val socket = Net.tcpConnect(host, port)
|
||||||
|
socket.writeUtf8("ping")
|
||||||
|
socket.flush()
|
||||||
|
socket.close()
|
||||||
|
accepted.await()
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals("ping", (result as ObjString).value)
|
||||||
|
} finally {
|
||||||
|
session.cancelAndJoin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,6 +28,8 @@ import java.net.InetAddress
|
|||||||
|
|
||||||
actual fun getSystemNetEngine(): LyngNetEngine = AndroidKtorNetEngine
|
actual fun getSystemNetEngine(): LyngNetEngine = AndroidKtorNetEngine
|
||||||
|
|
||||||
|
actual fun shutdownSystemNetEngine() {}
|
||||||
|
|
||||||
private object AndroidKtorNetEngine : LyngNetEngine {
|
private object AndroidKtorNetEngine : LyngNetEngine {
|
||||||
private val selectorManager: SelectorManager by lazy { ActorSelectorManager(Dispatchers.IO) }
|
private val selectorManager: SelectorManager by lazy { ActorSelectorManager(Dispatchers.IO) }
|
||||||
|
|
||||||
|
|||||||
@ -97,3 +97,5 @@ internal object UnsupportedLyngNetEngine : LyngNetEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect fun getSystemNetEngine(): LyngNetEngine
|
expect fun getSystemNetEngine(): LyngNetEngine
|
||||||
|
|
||||||
|
expect fun shutdownSystemNetEngine()
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
package net.sergeych.lyngio.net
|
package net.sergeych.lyngio.net
|
||||||
|
|
||||||
actual fun getSystemNetEngine(): LyngNetEngine = createNativeKtorNetEngine(
|
private val systemNetEngine: LyngNetEngine = createNativeKtorNetEngine(
|
||||||
isSupported = true,
|
isSupported = true,
|
||||||
isTcpAvailable = true,
|
isTcpAvailable = true,
|
||||||
isTcpServerAvailable = true,
|
isTcpServerAvailable = true,
|
||||||
isUdpAvailable = true,
|
isUdpAvailable = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
actual fun getSystemNetEngine(): LyngNetEngine = systemNetEngine
|
||||||
|
|
||||||
|
actual fun shutdownSystemNetEngine() {
|
||||||
|
shutdownNativeKtorNetEngine(systemNetEngine)
|
||||||
|
}
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import org.khronos.webgl.Uint8Array
|
|||||||
|
|
||||||
actual fun getSystemNetEngine(): LyngNetEngine = jsNodeNetEngineOrNull ?: UnsupportedLyngNetEngine
|
actual fun getSystemNetEngine(): LyngNetEngine = jsNodeNetEngineOrNull ?: UnsupportedLyngNetEngine
|
||||||
|
|
||||||
|
actual fun shutdownSystemNetEngine() {}
|
||||||
|
|
||||||
private val jsNodeNetEngineOrNull: LyngNetEngine? by lazy {
|
private val jsNodeNetEngineOrNull: LyngNetEngine? by lazy {
|
||||||
if (!isNodeRuntime()) return@lazy null
|
if (!isNodeRuntime()) return@lazy null
|
||||||
val net = requireNodeModule("net") ?: return@lazy null
|
val net = requireNodeModule("net") ?: return@lazy null
|
||||||
|
|||||||
@ -45,6 +45,8 @@ import java.net.InetAddress
|
|||||||
|
|
||||||
actual fun getSystemNetEngine(): LyngNetEngine = JvmKtorNetEngine
|
actual fun getSystemNetEngine(): LyngNetEngine = JvmKtorNetEngine
|
||||||
|
|
||||||
|
actual fun shutdownSystemNetEngine() {}
|
||||||
|
|
||||||
private object JvmKtorNetEngine : LyngNetEngine {
|
private object JvmKtorNetEngine : LyngNetEngine {
|
||||||
private val selectorManager: SelectorManager by lazy { ActorSelectorManager(Dispatchers.IO) }
|
private val selectorManager: SelectorManager by lazy { ActorSelectorManager(Dispatchers.IO) }
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
package net.sergeych.lyngio.net
|
package net.sergeych.lyngio.net
|
||||||
|
|
||||||
actual fun getSystemNetEngine(): LyngNetEngine = createNativeKtorNetEngine(
|
private val systemNetEngine: LyngNetEngine = createNativeKtorNetEngine(
|
||||||
isSupported = true,
|
isSupported = true,
|
||||||
isTcpAvailable = true,
|
isTcpAvailable = true,
|
||||||
isTcpServerAvailable = true,
|
isTcpServerAvailable = true,
|
||||||
isUdpAvailable = true,
|
isUdpAvailable = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
actual fun getSystemNetEngine(): LyngNetEngine = systemNetEngine
|
||||||
|
|
||||||
|
actual fun shutdownSystemNetEngine() {
|
||||||
|
shutdownNativeKtorNetEngine(systemNetEngine)
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
package net.sergeych.lyngio.net
|
package net.sergeych.lyngio.net
|
||||||
|
|
||||||
actual fun getSystemNetEngine(): LyngNetEngine = UnsupportedLyngNetEngine
|
actual fun getSystemNetEngine(): LyngNetEngine = UnsupportedLyngNetEngine
|
||||||
|
|
||||||
|
actual fun shutdownSystemNetEngine() {}
|
||||||
|
|||||||
@ -40,7 +40,10 @@ private class NativeKtorNetEngine(
|
|||||||
override val isTcpServerAvailable: Boolean,
|
override val isTcpServerAvailable: Boolean,
|
||||||
override val isUdpAvailable: Boolean,
|
override val isUdpAvailable: Boolean,
|
||||||
) : LyngNetEngine {
|
) : LyngNetEngine {
|
||||||
private val selectorManager: SelectorManager by lazy { SelectorManager(Dispatchers.Default) }
|
private var selectorManager: SelectorManager? = null
|
||||||
|
|
||||||
|
private fun selectorManager(): SelectorManager =
|
||||||
|
selectorManager ?: SelectorManager(Dispatchers.Default).also { selectorManager = it }
|
||||||
|
|
||||||
override suspend fun resolve(host: String, port: Int): List<LyngSocketAddress> {
|
override suspend fun resolve(host: String, port: Int): List<LyngSocketAddress> {
|
||||||
val rawAddress = InetSocketAddress(host, port).resolveAddress()
|
val rawAddress = InetSocketAddress(host, port).resolveAddress()
|
||||||
@ -62,7 +65,7 @@ private class NativeKtorNetEngine(
|
|||||||
noDelay: Boolean,
|
noDelay: Boolean,
|
||||||
): LyngTcpSocket {
|
): LyngTcpSocket {
|
||||||
val connectBlock: suspend () -> Socket = {
|
val connectBlock: suspend () -> Socket = {
|
||||||
aSocket(selectorManager).tcp().connect(host, port) {
|
aSocket(selectorManager()).tcp().connect(host, port) {
|
||||||
this.noDelay = noDelay
|
this.noDelay = noDelay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +80,7 @@ private class NativeKtorNetEngine(
|
|||||||
reuseAddress: Boolean,
|
reuseAddress: Boolean,
|
||||||
): LyngTcpServer {
|
): LyngTcpServer {
|
||||||
val bindHost = host ?: "0.0.0.0"
|
val bindHost = host ?: "0.0.0.0"
|
||||||
val server = aSocket(selectorManager).tcp().bind(bindHost, port) {
|
val server = aSocket(selectorManager()).tcp().bind(bindHost, port) {
|
||||||
backlogSize = backlog
|
backlogSize = backlog
|
||||||
this.reuseAddress = reuseAddress
|
this.reuseAddress = reuseAddress
|
||||||
}
|
}
|
||||||
@ -86,11 +89,16 @@ private class NativeKtorNetEngine(
|
|||||||
|
|
||||||
override suspend fun udpBind(host: String?, port: Int, reuseAddress: Boolean): LyngUdpSocket {
|
override suspend fun udpBind(host: String?, port: Int, reuseAddress: Boolean): LyngUdpSocket {
|
||||||
val bindHost = host ?: "0.0.0.0"
|
val bindHost = host ?: "0.0.0.0"
|
||||||
val socket = aSocket(selectorManager).udp().bind(bindHost, port) {
|
val socket = aSocket(selectorManager()).udp().bind(bindHost, port) {
|
||||||
this.reuseAddress = reuseAddress
|
this.reuseAddress = reuseAddress
|
||||||
}
|
}
|
||||||
return NativeLyngUdpSocket(socket)
|
return NativeLyngUdpSocket(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun shutdown() {
|
||||||
|
selectorManager?.close()
|
||||||
|
selectorManager = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NativeLyngTcpSocket(
|
private class NativeLyngTcpSocket(
|
||||||
@ -214,3 +222,7 @@ private fun ByteArray.toIpHostString(): String = when (size) {
|
|||||||
}
|
}
|
||||||
else -> error("Unsupported IP address length: $size")
|
else -> error("Unsupported IP address length: $size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun shutdownNativeKtorNetEngine(engine: LyngNetEngine) {
|
||||||
|
(engine as? NativeKtorNetEngine)?.shutdown()
|
||||||
|
}
|
||||||
|
|||||||
@ -151,8 +151,10 @@ class ImportManager(
|
|||||||
fun copy(): ImportManager =
|
fun copy(): ImportManager =
|
||||||
op.withLock {
|
op.withLock {
|
||||||
ImportManager(rootScope, securityManager).apply {
|
ImportManager(rootScope, securityManager).apply {
|
||||||
imports.putAll(this@ImportManager.imports)
|
for ((name, entry) in this@ImportManager.imports) {
|
||||||
|
imports[name] = Entry(entry.packageName, entry.builder, entry.cachedScope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user