Skip to content

Commit 2c39132

Browse files
committed
Fix #255
1 parent 4e0d30a commit 2c39132

File tree

6 files changed

+165
-69
lines changed

6 files changed

+165
-69
lines changed

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ shadowJarVersion=7.0.0
1010
kotlinxSerializationVersion=1.1.0
1111
ktlintGradleVersion=10.0.0
1212
ktlintVersion=0.40.0
13-
publishPluginVersion=0.0.27-dev
13+
publishPluginVersion=0.0.29-dev
1414
junitVersion=5.7.1
1515
slf4jVersion=1.7.30
1616
logbackVersion=1.2.3
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

jupyter-lib/kotlin-jupyter-api-gradle-plugin/build.gradle.kts

+20-7
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,21 @@ val saveVersion by tasks.registering {
4848
}
4949
}
5050

51-
tasks.processResources {
52-
dependsOn(saveVersion)
53-
}
51+
tasks {
52+
processResources {
53+
dependsOn(saveVersion)
54+
}
55+
56+
test {
57+
useJUnitPlatform()
58+
testLogging {
59+
events("passed", "skipped", "failed")
60+
}
61+
}
5462

55-
tasks.test {
56-
useJUnitPlatform()
57-
testLogging {
58-
events("passed", "skipped", "failed")
63+
register<Jar>("sourceJar") {
64+
archiveClassifier.set("sources")
65+
from(sourceSets.named("main").get().allSource)
5966
}
6067
}
6168

@@ -90,6 +97,12 @@ pluginBundle {
9097
}
9198

9299
publishing {
100+
publications {
101+
withType<MavenPublication> {
102+
artifact(tasks["sourceJar"])
103+
}
104+
}
105+
93106
repositories {
94107
(rootProject.findProperty("localPublicationsRepo") as? java.nio.file.Path)?.let {
95108
maven {

jupyter-lib/kotlin-jupyter-api-gradle-plugin/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/plugin/ApiGradlePlugin.kt

+31-18
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package org.jetbrains.kotlinx.jupyter.api.plugin
22

33
import org.gradle.api.Plugin
44
import org.gradle.api.Project
5+
import org.gradle.api.tasks.Copy
56
import org.gradle.kotlin.dsl.findByType
67
import org.gradle.kotlin.dsl.invoke
8+
import org.gradle.kotlin.dsl.named
79
import org.gradle.kotlin.dsl.register
810
import org.gradle.kotlin.dsl.repositories
911
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@@ -41,37 +43,48 @@ class ApiGradlePlugin : Plugin<Project> {
4143
}
4244

4345
val resourcesTaskName = "processJupyterApiResources"
44-
fun registerResourceTask() {
45-
register<JupyterApiResourcesTask>(resourcesTaskName) {
46-
val kaptKotlinTask = findByName("kaptKotlin")
47-
if (kaptKotlinTask != null) {
48-
dependsOn(kaptKotlinTask)
49-
kaptKotlinTask.dependsOn(cleanJupyterTask)
50-
kaptKotlinTask.outputs.dir(jupyterBuildPath)
46+
fun registerResourceTask(): JupyterApiResourcesTask {
47+
findByName(resourcesTaskName) ?: register<JupyterApiResourcesTask>(resourcesTaskName)
48+
return named<JupyterApiResourcesTask>(resourcesTaskName).get()
49+
}
50+
51+
fun dependOnProcessingTask(processTaskName: String) {
52+
val jupyterTask = registerResourceTask()
53+
tasks.named<Copy>(processTaskName) {
54+
dependsOn(resourcesTaskName)
55+
from(jupyterTask.outputDir)
56+
}
57+
}
58+
59+
fun dependOnKapt(kaptTaskName: String) {
60+
registerResourceTask()
61+
tasks.whenObjectAdded {
62+
val addedTask = this
63+
if (addedTask.name == kaptTaskName) {
64+
tasks.named(resourcesTaskName) {
65+
dependsOn(addedTask)
66+
addedTask.dependsOn(cleanJupyterTask)
67+
addedTask.outputs.dir(jupyterBuildPath)
68+
}
5169
}
5270
}
5371
}
5472

5573
// apply configuration to JVM-only project
5674
plugins.withId("org.jetbrains.kotlin.jvm") {
57-
// Task should be registered after plugin is applied
58-
registerResourceTask()
59-
named("processResources") {
60-
dependsOn(resourcesTaskName)
61-
}
75+
dependOnProcessingTask("processResources")
76+
dependOnKapt("kaptKotlin")
6277
}
6378

6479
// apply only to multiplatform plugin
6580
plugins.withId("org.jetbrains.kotlin.multiplatform") {
66-
// Task should be registered after plugin is applied
67-
registerResourceTask()
6881
extensions.findByType<KotlinMultiplatformExtension>()?.apply {
69-
val jvmTargetName = targets.filterIsInstance<KotlinJvmTarget>().firstOrNull()?.name
70-
?: error("Single JVM target not found in a multiplatform project")
71-
named(jvmTargetName + "ProcessResources") {
72-
dependsOn(resourcesTaskName)
82+
targets.whenObjectAdded {
83+
if (this !is KotlinJvmTarget) return@whenObjectAdded
84+
dependOnProcessingTask(this.name + "ProcessResources")
7385
}
7486
}
87+
dependOnKapt("kaptKotlinJvm")
7588
}
7689
}
7790
}

jupyter-lib/kotlin-jupyter-api-gradle-plugin/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/plugin/tasks/JupyterApiResourcesTask.kt

+4-30
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ import com.google.gson.Gson
44
import org.gradle.api.DefaultTask
55
import org.gradle.api.tasks.Input
66
import org.gradle.api.tasks.OutputDirectory
7-
import org.gradle.api.tasks.SourceSet
8-
import org.gradle.api.tasks.SourceSetContainer
97
import org.gradle.api.tasks.TaskAction
10-
import org.gradle.kotlin.dsl.findByType
11-
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
12-
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
138
import org.jetbrains.kotlinx.jupyter.api.plugin.ApiGradlePlugin
149
import java.io.File
1510

@@ -31,30 +26,7 @@ open class JupyterApiResourcesTask : DefaultTask() {
3126
var libraryDefinitions: List<String> = emptyList()
3227

3328
@OutputDirectory
34-
val outputDir: File
35-
36-
init {
37-
val sourceSets = project.extensions.getByName("sourceSets") as SourceSetContainer
38-
when {
39-
project.plugins.findPlugin("org.jetbrains.kotlin.jvm") != null -> {
40-
val mainSourceSet: SourceSet = sourceSets.named("main").get()
41-
outputDir = mainSourceSet.output.resourcesDir?.resolve("META-INF/kotlin-jupyter-libraries")
42-
?: throw IllegalStateException("No resources dir for main source set")
43-
}
44-
project.plugins.findPlugin("org.jetbrains.kotlin.multiplatform") != null -> {
45-
val mppExtension = project.extensions.findByType<KotlinMultiplatformExtension>()
46-
?: error("Kotlin MPP extension not found")
47-
val jvmTargetName = mppExtension.targets.filterIsInstance<KotlinJvmTarget>().firstOrNull()?.name
48-
?: error("Single JVM target not found in a multiplatform project")
49-
// TODO properly resolve resource directory
50-
outputDir = project.buildDir.resolve("processedResources/$jvmTargetName/main")
51-
.resolve("META-INF/kotlin-jupyter-libraries")
52-
}
53-
else -> {
54-
error("Kotlin plugin not found in the project")
55-
}
56-
}
57-
}
29+
val outputDir: File = project.buildDir.resolve("jupyterProcessedResources")
5830

5931
@TaskAction
6032
fun createDescriptions() {
@@ -64,7 +36,9 @@ open class JupyterApiResourcesTask : DefaultTask() {
6436
) + getScanResultFromAnnotations()
6537
val json = Gson().toJson(resultObject)
6638

67-
val libFile = outputDir.resolve("libraries.json")
39+
val jupyterDir = outputDir.resolve("META-INF/kotlin-jupyter-libraries")
40+
val libFile = jupyterDir.resolve("libraries.json")
41+
libFile.parentFile.mkdirs()
6842
libFile.writeText(json)
6943
}
7044

jupyter-lib/kotlin-jupyter-api-gradle-plugin/src/test/kotlin/org/jetbrains/kotlinx/jupyter/api/plugin/test/ResourcesTaskTests.kt

+108-12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class ResourcesTaskTests {
2323
val buildFile = projectDir.resolve("build.gradle")
2424
val taskSetupIndented = taskSetup.prependIndent(" ".repeat(2))
2525
val buildFileText = """
26-
$PLUGINS_BLOCK
26+
${pluginsBlock()}
2727
2828
tasks {
2929
$JUPYTER_RESOURCES_TASK_NAME {
@@ -34,12 +34,15 @@ class ResourcesTaskTests {
3434
buildFile.writeText(buildFileText)
3535
}
3636

37-
private fun runResourcesTask(args: Array<String>? = null): BuildResult {
37+
private fun runResourcesTask(args: Array<String>? = null, type: String = ""): BuildResult {
3838
val arguments = args?.toMutableList() ?: mutableListOf(
3939
"-Pkotlin.jupyter.add.api=false",
40-
"-Pkotlin.jupyter.add.scanner=false"
40+
"-Pkotlin.jupyter.add.scanner=false",
41+
"--stacktrace",
42+
"--info"
4143
)
42-
arguments.add(0, RESOURCES_TASK_NAME)
44+
val taskName = RESOURCES_TASK_NAME.withPrefix(type)
45+
arguments.add(0, taskName)
4346

4447
return GradleRunner.create()
4548
.withProjectDir(projectDir)
@@ -49,8 +52,8 @@ class ResourcesTaskTests {
4952
.build()
5053
}
5154

52-
private fun assertLibrariesJsonContents(expected: LibrariesScanResult) {
53-
val librariesJsonText = projectDir.resolve(BUILD_LIBRARIES_JSON_PATH).readText()
55+
private fun assertLibrariesJsonContents(expected: LibrariesScanResult, type: String = "") {
56+
val librariesJsonText = projectDir.resolve(buildLibrariesJsonPath(type)).readText()
5457
val libraryInfo = Json.decodeFromString<LibrariesScanResult>(librariesJsonText)
5558

5659
assertEquals(expected, libraryInfo)
@@ -111,7 +114,7 @@ class ResourcesTaskTests {
111114
val apiAnnotations = jarFile("api-annotations")
112115
buildFile.writeText(
113116
"""
114-
$PLUGINS_BLOCK
117+
${pluginsBlock()}
115118
116119
dependencies {
117120
implementation(files("$apiJar"))
@@ -149,6 +152,89 @@ class ResourcesTaskTests {
149152
)
150153
}
151154

155+
@Test
156+
fun `check annotations in MPP`() {
157+
val version = ClassLoader.getSystemClassLoader().getResource("VERSION")?.readText().orEmpty()
158+
159+
val propertiesFile = projectDir.resolve("properties.gradle")
160+
propertiesFile.writeText(
161+
"""
162+
kapt.verbose=true
163+
""".trimIndent()
164+
)
165+
166+
val buildFile = projectDir.resolve("build.gradle.kts")
167+
168+
fun jarFile(name: String): String {
169+
return File("../$name/build/libs/$name-$version.jar").canonicalFile.absolutePath.replace("\\", "/")
170+
}
171+
172+
val apiJar = jarFile("api")
173+
val apiAnnotations = jarFile("api-annotations")
174+
buildFile.writeText(
175+
"""
176+
plugins {
177+
kotlin("multiplatform") version "$KOTLIN_VERSION"
178+
id("org.jetbrains.kotlin.jupyter.api")
179+
}
180+
181+
kotlin {
182+
jvm {
183+
compilations.all {
184+
kotlinOptions.jvmTarget = "11"
185+
}
186+
}
187+
js(LEGACY) {
188+
binaries.executable()
189+
browser()
190+
}
191+
sourceSets {
192+
val commonMain by getting
193+
val commonTest by getting
194+
val jvmMain by getting {
195+
dependencies {
196+
implementation(files("$apiJar"))
197+
implementation(files("$apiAnnotations"))
198+
}
199+
dependencies.add("kapt", files("$apiAnnotations"))
200+
}
201+
val jvmTest by getting
202+
val jsMain by getting
203+
val jsTest by getting
204+
}
205+
}
206+
""".trimIndent()
207+
)
208+
209+
val srcDir = projectDir.resolve("src/jvmMain/kotlin")
210+
srcDir.mkdirs()
211+
212+
val integrationKt = srcDir.resolve("pack").resolve("Integration.kt")
213+
integrationKt.parentFile.mkdirs()
214+
integrationKt.writeText(
215+
"""
216+
package pack
217+
218+
import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
219+
import org.jetbrains.kotlinx.jupyter.api.*
220+
import org.jetbrains.kotlinx.jupyter.api.libraries.*
221+
222+
@JupyterLibrary
223+
class Integration : JupyterIntegration({
224+
import("org.my.lib.*")
225+
})
226+
""".trimIndent()
227+
)
228+
runResourcesTask(type = "jvm")
229+
230+
assertLibrariesJsonContents(
231+
LibrariesScanResult(
232+
producers = listOf("pack.Integration").map(::LibrariesProducerDeclaration)
233+
),
234+
"jvm"
235+
)
236+
}
237+
152238
@Test
153239
fun `check extension`() {
154240
val version = "0.8.3.202"
@@ -157,7 +243,7 @@ class ResourcesTaskTests {
157243

158244
buildFile.writeText(
159245
"""
160-
$PLUGINS_BLOCK
246+
${pluginsBlock()}
161247
162248
kotlinJupyter {
163249
addApiDependency("$version")
@@ -195,17 +281,27 @@ class ResourcesTaskTests {
195281
}
196282

197283
companion object {
284+
private const val KOTLIN_VERSION = "1.5.20"
198285
private const val RESOURCES_TASK_NAME = "processResources"
199286
private const val JUPYTER_RESOURCES_TASK_NAME = "processJupyterApiResources"
200287

201-
private const val MAIN_SOURCE_SET_BUILD_RESOURCES_PATH = "build/resources/main"
202-
private const val BUILD_LIBRARIES_JSON_PATH = "$MAIN_SOURCE_SET_BUILD_RESOURCES_PATH/$KOTLIN_JUPYTER_RESOURCES_PATH/$KOTLIN_JUPYTER_LIBRARIES_FILE_NAME"
288+
private fun mainSourceSetBuildResourcesPath(type: String = ""): String {
289+
return if (type.isEmpty()) {
290+
"build/resources/main"
291+
} else {
292+
"build/processedResources/$type/main"
293+
}
294+
}
295+
private fun buildLibrariesJsonPath(type: String = "") = "${mainSourceSetBuildResourcesPath(type)}/$KOTLIN_JUPYTER_RESOURCES_PATH/$KOTLIN_JUPYTER_LIBRARIES_FILE_NAME"
203296

204-
private val PLUGINS_BLOCK = """
297+
private fun pluginsBlock(ktPluginId: String = "jvm") = """
205298
plugins {
206-
id 'org.jetbrains.kotlin.jvm' version '1.4.20'
299+
id 'org.jetbrains.kotlin.$ktPluginId' version '$KOTLIN_VERSION'
207300
id 'org.jetbrains.kotlin.jupyter.api'
208301
}
209302
""".trimIndent()
303+
304+
private fun String.withPrefix(prefix: String) =
305+
if (prefix.isEmpty()) this else prefix + capitalize()
210306
}
211307
}

0 commit comments

Comments
 (0)