@@ -6,43 +6,63 @@ package com.tschuchort.compiletesting
66import org.jetbrains.kotlin.ksp.KotlinSymbolProcessingCommandLineProcessor
77import org.jetbrains.kotlin.ksp.KotlinSymbolProcessingComponentRegistrar
88import org.jetbrains.kotlin.ksp.processing.SymbolProcessor
9+ import java.io.File
910
1011private const val KSP_PLUGIN_ID = " org.jetbrains.kotlin.ksp"
1112
12- fun KotlinCompilation.symbolProcessor (
13+ private fun KotlinCompilation.initAndGetKspConfig (): KspConfiguration {
14+ val config = KspConfiguration (workingDir.resolve(" ksp" ))
15+ if (config.workingDir.exists()) {
16+ // already configured, just return
17+ return config
18+ }
19+ config.classesOutDir.mkdirs()
20+ config.sourcesOurDir.mkdirs()
21+ config.syntheticSources.mkdirs()
22+ val kspOptions = listOf (
23+ PluginOption (KSP_PLUGIN_ID , " apclasspath" , config.syntheticSources.path),
24+ PluginOption (KSP_PLUGIN_ID , " classes" , config.classesOutDir.path),
25+ PluginOption (KSP_PLUGIN_ID , " sources" , config.sourcesOurDir.path)
26+ )
27+ compilerPlugins = compilerPlugins + KotlinSymbolProcessingComponentRegistrar ()
28+ commandLineProcessors = commandLineProcessors + listOf (KotlinSymbolProcessingCommandLineProcessor ())
29+ pluginOptions = pluginOptions + kspOptions
30+ return config
31+ }
32+
33+ fun KotlinCompilation.symbolProcessors (
1334 vararg processors : Class <out SymbolProcessor >
1435) {
1536 check(processors.isNotEmpty()) {
1637 " Must provide at least 1 symbol processor"
1738 }
18- val kspWorkingDir = workingDir.resolve( " ksp " )
39+ val config = initAndGetKspConfig( )
1940
2041 // create a fake classpath that references our symbol processor
21- val processorClasspath = kspWorkingDir.resolve( " synthetic-ksp-service " ) .apply {
42+ config.syntheticSources .apply {
2243 resolve(" META-INF/services/org.jetbrains.kotlin.ksp.processing.SymbolProcessor" ).apply {
2344 parentFile.mkdirs()
24- val processorNames = processors.joinToString(System .lineSeparator()) {
45+ // keep existing ones in case this function is called multiple times
46+ val existing = if (exists()) {
47+ readLines(Charsets .UTF_8 )
48+ } else {
49+ emptyList()
50+ }
51+ val processorNames = existing + processors.map {
2552 it.typeName
2653 }
2754 writeText(
28- processorNames
55+ processorNames.joinToString( System .lineSeparator())
2956 )
3057 }
3158 }
32-
33- val classesFolder = kspWorkingDir.resolve(" outClasses" ).also {
34- it.mkdirs()
35- }
36- val sourceFolder = kspWorkingDir.resolve(" outSources" ).also {
37- it.mkdirs()
38- }
39- val kspOptions = listOf (
40- PluginOption (KSP_PLUGIN_ID , " apclasspath" , processorClasspath.path),
41- PluginOption (KSP_PLUGIN_ID , " classes" , classesFolder.path),
42- PluginOption (KSP_PLUGIN_ID , " sources" , sourceFolder.path)
43- )
44- compilerPlugins = compilerPlugins + KotlinSymbolProcessingComponentRegistrar ()
45- commandLineProcessors = commandLineProcessors + listOf (KotlinSymbolProcessingCommandLineProcessor ())
46- pluginOptions = pluginOptions + kspOptions
4759 this .kaptSourceDir
4860}
61+
62+ private data class KspConfiguration (
63+ val workingDir : File
64+ ) {
65+ val classesOutDir = workingDir.resolve(" classesOutput" )
66+ val sourcesOurDir = workingDir.resolve(" sourcesOutput" )
67+ val syntheticSources = workingDir.resolve(" synthetic-ksp-service" )
68+ }
0 commit comments