Skip to content

Commit 0b89eec

Browse files
committed
Don't depend on http4k in shared-compiler module and refactor libraries processing modules
1 parent 36b2dbb commit 0b89eec

31 files changed

+370
-335
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ out/
2222
/teamcity-artifacts/
2323

2424
# Folder with library descriptors
25-
libraries/
25+
/libraries/
2626

2727
# Gradle caches and internal files
2828
.gradle/

build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ dependencies {
5555
// Clikt library for parsing output magics
5656
implementation(libs.clikt)
5757

58+
// Http4k for resolving library descriptors
59+
implementation(libs.bundles.http4k) {
60+
exclude(group = "org.jetbrains.kotlin")
61+
}
62+
5863
// Serialization implementation for kernel code
5964
implementation(libs.serialization.json)
6065

jupyter-lib/shared-compiler/build.gradle.kts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ repositories {
1212

1313
dependencies {
1414
// Internal dependencies
15-
api(projects.api)
16-
api(projects.lib)
17-
api(projects.commonDependencies)
15+
api(projects.api) { isTransitive = false }
16+
api(projects.lib) { isTransitive = false }
17+
api(projects.commonDependencies) { isTransitive = false }
1818

1919
// Standard dependencies
2020
compileOnly(libs.kotlin.stable.stdlib)
@@ -27,6 +27,9 @@ dependencies {
2727
compileOnly(libs.kotlin.dev.scriptingCompilerImplUnshaded)
2828
compileOnly(libs.kotlin.dev.scriptingDependencies) { isTransitive = false }
2929

30+
// Serialization runtime
31+
compileOnly(libs.serialization.json)
32+
3033
// Serialization compiler plugin (for notebooks, not for kernel code)
3134
compileOnly(libs.serialization.dev.unshadedPlugin)
3235

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.jetbrains.kotlinx.jupyter.libraries
2+
3+
object ByNothingLibraryResolutionInfo : LibraryResolutionInfo {
4+
override val key: String
5+
get() = "nothing_"
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.jetbrains.kotlinx.jupyter.libraries
2+
3+
import org.jetbrains.kotlinx.jupyter.api.libraries.LibraryDefinition
4+
5+
abstract class ChainedLibraryResolver(private val parent: LibraryResolver? = null) : LibraryResolver {
6+
protected abstract fun tryResolve(reference: LibraryReference, arguments: List<Variable>): LibraryDefinition?
7+
protected open fun save(reference: LibraryReference, definition: LibraryDefinition) {}
8+
protected open fun shouldResolve(reference: LibraryReference): Boolean = true
9+
10+
override fun resolve(reference: LibraryReference, arguments: List<Variable>): LibraryDefinition? {
11+
val shouldBeResolved = shouldResolve(reference)
12+
if (shouldBeResolved) {
13+
val result = tryResolve(reference, arguments)
14+
if (result != null) return result
15+
}
16+
17+
val parentResult = parent?.resolve(reference, arguments) ?: return null
18+
if (shouldBeResolved) {
19+
save(reference, parentResult)
20+
}
21+
22+
return parentResult
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,7 @@
11
package org.jetbrains.kotlinx.jupyter.libraries
22

3-
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelVersion
4-
import org.jetbrains.kotlinx.jupyter.api.libraries.LibraryDefinition
53
import org.jetbrains.kotlinx.jupyter.api.libraries.LibraryDefinitionProducer
6-
import org.jetbrains.kotlinx.jupyter.exceptions.ReplException
74

85
interface LibrariesProcessor {
96
fun processNewLibraries(arg: String): List<LibraryDefinitionProducer>
107
}
11-
12-
class LibrariesProcessorImpl(
13-
private val libraries: LibraryResolver?,
14-
private val kernelVersion: KotlinKernelVersion?,
15-
) : LibrariesProcessor {
16-
17-
/**
18-
* Split a command argument into a set of library calls
19-
* Need special processing of ',' to skip call argument delimiters in brackets
20-
* E.g. "use lib1(3), lib2(2, 5)" should split into "lib1(3)" and "lib(2, 5)", not into "lib1(3)", "lib(2", "5)"
21-
*/
22-
private fun splitLibraryCalls(text: String): List<String> {
23-
var i = 0
24-
var prev = 0
25-
var commaDepth = 0
26-
val result = mutableListOf<String>()
27-
val delimiters = charArrayOf(',', '(', ')')
28-
while (true) {
29-
i = text.indexOfAny(delimiters, i)
30-
if (i == -1) {
31-
val res = text.substring(prev, text.length).trim()
32-
if (res.isNotEmpty()) {
33-
result.add(res)
34-
}
35-
return result
36-
}
37-
when (text[i]) {
38-
',' -> if (commaDepth == 0) {
39-
val res = text.substring(prev, i).trim()
40-
if (res.isNotEmpty()) {
41-
result.add(res)
42-
}
43-
prev = i + 1
44-
}
45-
'(' -> commaDepth++
46-
')' -> commaDepth--
47-
}
48-
i++
49-
}
50-
}
51-
52-
private fun checkKernelVersionRequirements(name: String, library: LibraryDefinition) {
53-
library.minKernelVersion?.let { minVersion ->
54-
kernelVersion?.let { currentVersion ->
55-
if (currentVersion < minVersion) {
56-
throw ReplException("Library '$name' requires at least $minVersion version of kernel. Current kernel version is $currentVersion. Please update kernel")
57-
}
58-
}
59-
}
60-
}
61-
62-
override fun processNewLibraries(arg: String): List<LibraryDefinitionProducer> =
63-
splitLibraryCalls(arg).map {
64-
val (libRef, vars) = parseReferenceWithArgs(it)
65-
val library = libraries?.resolve(libRef, vars)
66-
?: throw ReplException("Unknown library '$libRef'")
67-
68-
checkKernelVersionRequirements(libRef.toString(), library)
69-
70-
TrivialLibraryDefinitionProducer(library)
71-
}
72-
}
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,5 @@
11
package org.jetbrains.kotlinx.jupyter.libraries
22

3-
import java.io.File
4-
import java.net.URL
5-
import java.util.concurrent.ConcurrentHashMap
6-
7-
abstract class LibraryResolutionInfo(
8-
private val typeKey: String
9-
) : LibraryCacheable {
10-
class ByNothing : LibraryResolutionInfo("nothing") {
11-
override val args: List<Variable> = listOf()
12-
}
13-
14-
class ByURL(val url: URL) : LibraryResolutionInfo("url") {
15-
override val args = listOf(Variable("url", url.toString()))
16-
override val shouldBeCachedLocally get() = false
17-
}
18-
19-
class ByFile(val file: File) : LibraryResolutionInfo("file") {
20-
override val args = listOf(Variable("file", file.path))
21-
override val shouldBeCachedLocally get() = false
22-
}
23-
24-
class ByDir(val librariesDir: File) : LibraryResolutionInfo("bundled") {
25-
override val args = listOf(Variable("dir", librariesDir.path))
26-
override val shouldBeCachedLocally get() = false
27-
}
28-
29-
class ByGitRef(private val ref: String) : LibraryResolutionInfo("ref") {
30-
override val valueKey: String
31-
get() = sha
32-
33-
val sha: String by lazy {
34-
val (resolvedSha, _) = KERNEL_LIBRARIES.getLatestCommitToLibraries(ref, null) ?: return@lazy ref
35-
resolvedSha
36-
}
37-
38-
override val args = listOf(Variable("ref", ref))
39-
}
40-
41-
class Default(val string: String = "") : LibraryResolutionInfo("default") {
42-
override val args: List<Variable> = listOf()
43-
override val shouldBeCachedLocally get() = false
44-
}
45-
46-
protected abstract val args: List<Variable>
47-
protected open val valueKey: String
48-
get() = args.joinToString { it.value }
49-
50-
val key: String by lazy { "${typeKey}_${replaceForbiddenChars(valueKey)}" }
51-
52-
override fun hashCode(): Int {
53-
return key.hashCode()
54-
}
55-
56-
override fun equals(other: Any?): Boolean {
57-
if (this === other) return true
58-
if (javaClass != other?.javaClass) return false
59-
60-
other as LibraryResolutionInfo
61-
62-
return valueKey == other.valueKey
63-
}
64-
65-
override fun toString(): String {
66-
return typeKey +
67-
when {
68-
args.isEmpty() -> ""
69-
args.size == 1 -> "[${args[0].value}]"
70-
else -> args.joinToString(", ", "[", "]") { "${it.name}=${it.value}" }
71-
}
72-
}
73-
74-
companion object {
75-
private val gitRefsCache = ConcurrentHashMap<String, ByGitRef>()
76-
77-
fun getInfoByRef(ref: String): ByGitRef {
78-
return gitRefsCache.getOrPut(ref, { ByGitRef(ref) })
79-
}
80-
81-
fun replaceForbiddenChars(string: String): String {
82-
return string.replace("""[<>/\\:"|?*]""".toRegex(), "_")
83-
}
84-
}
3+
interface LibraryResolutionInfo : LibraryCacheable {
4+
val key: String
855
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.jetbrains.kotlinx.jupyter.libraries
2+
3+
import org.jetbrains.kotlinx.jupyter.api.libraries.LibraryDefinition
4+
5+
interface LibraryResolver {
6+
fun resolve(reference: LibraryReference, arguments: List<Variable>): LibraryDefinition?
7+
}
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,7 @@
11
package org.jetbrains.kotlinx.jupyter.libraries
22

3-
import org.jetbrains.kotlinx.jupyter.common.getHttp
4-
import java.io.File
5-
import java.net.URL
6-
73
interface ResolutionInfoProvider {
84
var fallback: LibraryResolutionInfo
95

106
fun get(string: String): LibraryResolutionInfo
11-
12-
companion object {
13-
fun withDefaultDirectoryResolution(dir: File) = StandardResolutionInfoProvider(
14-
LibraryResolutionInfo.ByDir(dir)
15-
)
16-
17-
// Used in Kotlin Jupyter plugin for IDEA
18-
@Suppress("unused")
19-
fun withDefaultGitRefResolution(ref: String) = StandardResolutionInfoProvider(
20-
LibraryResolutionInfo.getInfoByRef(ref)
21-
)
22-
}
23-
}
24-
25-
object EmptyResolutionInfoProvider : ResolutionInfoProvider {
26-
private val fallbackInfo = LibraryResolutionInfo.ByNothing()
27-
28-
override var fallback: LibraryResolutionInfo
29-
get() = fallbackInfo
30-
set(_) {}
31-
32-
override fun get(string: String): LibraryResolutionInfo {
33-
if (string.isEmpty()) return fallback
34-
return LibraryResolutionInfo.getInfoByRef(string)
35-
}
36-
}
37-
38-
class StandardResolutionInfoProvider(override var fallback: LibraryResolutionInfo) : ResolutionInfoProvider {
39-
override fun get(string: String): LibraryResolutionInfo {
40-
if (string.isEmpty()) return fallback
41-
return tryGetAsRef(string) ?: tryGetAsDir(string) ?: tryGetAsFile(string) ?: tryGetAsURL(string) ?: fallback
42-
}
43-
44-
private fun tryGetAsRef(ref: String): LibraryResolutionInfo? {
45-
return if (KERNEL_LIBRARIES.checkRefExistence(ref)) LibraryResolutionInfo.getInfoByRef(ref) else null
46-
}
47-
48-
private fun tryGetAsDir(dirName: String): LibraryResolutionInfo? {
49-
val file = File(dirName)
50-
return if (file.isDirectory) LibraryResolutionInfo.ByDir(file) else null
51-
}
52-
53-
private fun tryGetAsFile(fileName: String): LibraryResolutionInfo? {
54-
val file = File(fileName)
55-
return if (file.isFile) LibraryResolutionInfo.ByFile(file) else null
56-
}
57-
58-
private fun tryGetAsURL(url: String): LibraryResolutionInfo? {
59-
val response = getHttp(url)
60-
return if (response.status.successful) LibraryResolutionInfo.ByURL(URL(url)) else null
61-
}
627
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.jetbrains.kotlinx.jupyter.libraries
2+
3+
class ResolutionInfoSwitcher<T>(private val infoProvider: ResolutionInfoProvider, initialSwitchVal: T, private val switcher: (T) -> LibraryResolutionInfo) {
4+
private val defaultInfoCache = hashMapOf<T, LibraryResolutionInfo>()
5+
6+
var switch: T = initialSwitchVal
7+
set(value) {
8+
infoProvider.fallback = defaultInfoCache.getOrPut(value) { switcher(value) }
9+
field = value
10+
}
11+
12+
companion object {
13+
// Used in Kotlin Jupyter plugin for IDEA
14+
@Suppress("unused")
15+
fun noop(provider: ResolutionInfoProvider): ResolutionInfoSwitcher<DefaultInfoSwitch> {
16+
return ResolutionInfoSwitcher(provider, DefaultInfoSwitch.GIT_REFERENCE) {
17+
provider.fallback
18+
}
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)