Skip to content
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
9 changes: 7 additions & 2 deletions gratatouille-gradle-plugin/api/gratatouille-gradle-plugin.api
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
public abstract interface class gratatouille/gradle/ClassloaderIsolationSpec {
public abstract fun getConfigurationName ()Lorg/gradle/api/provider/Property;
public abstract fun getCoordinates ()Lorg/gradle/api/provider/Property;
}

public abstract interface class gratatouille/gradle/CodeGenerationSpec {
public abstract fun classLoaderIsolation ()V
public abstract fun classLoaderIsolation (Ljava/lang/String;)V
public abstract fun classLoaderIsolation (Lorg/gradle/api/Action;)V
public abstract fun getAddDependencies ()Lorg/gradle/api/provider/Property;
public abstract fun getEnableKotlinxSerialization ()Lorg/gradle/api/provider/Property;
}
Expand Down Expand Up @@ -80,7 +85,7 @@ public abstract class gratatouille/gradle/WiringPlugin : org/gradle/api/Plugin {
public final class gratatouille/gradle/internal/DefaultCodeGenerationSpec : gratatouille/gradle/CodeGenerationSpec {
public fun <init> (Lorg/gradle/api/Project;)V
public fun classLoaderIsolation ()V
public fun classLoaderIsolation (Ljava/lang/String;)V
public fun classLoaderIsolation (Lorg/gradle/api/Action;)V
public fun getAddDependencies ()Lorg/gradle/api/provider/Property;
public fun getEnableKotlinxSerialization ()Lorg/gradle/api/provider/Property;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package gratatouille.gradle

import org.gradle.api.provider.Property

interface ClassloaderIsolationSpec {
/**
* The coordinates of the artifact where the task implementations are in the form group:artifact:version.
*
* Default: project.group:project.name:project.version
*/
val coordinates: Property<String>

/**
* Unique name to identify the configuration
*
* Defaults to a name based on [coordinates]
*/
val configurationName: Property<String>

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gratatouille.gradle

import org.gradle.api.Action
import org.gradle.api.provider.Property

interface CodeGenerationSpec {
Expand All @@ -20,7 +21,7 @@ interface CodeGenerationSpec {
fun classLoaderIsolation()

/**
* Enables classloader isolation.
* Enables classloader isolation
*/
fun classLoaderIsolation(publishedCoordinates: String)
fun classLoaderIsolation(action: Action<ClassloaderIsolationSpec>)
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
package gratatouille.gradle.internal

import gratatouille.gradle.ClassloaderIsolationSpec
import gratatouille.gradle.CodeGenerationSpec
import gratatouille.gradle.tasks.registerZipFilesTask
import gratatouille.wiring.capitalizeFirstLetter
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.attributes.Usage
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.tasks.bundling.AbstractArchiveTask

class DefaultCodeGenerationSpec(private val project: Project): CodeGenerationSpec {
internal var publishedCoordinates: String? = null
internal var classloaderIsolationSpec: ClassloaderIsolationSpec? = null

override val enableKotlinxSerialization = project.objects.property(Boolean::class.java)

override val addDependencies = project.objects.property(Boolean::class.java)

/**
* Enables ClassLoader isolation mode using the project group, name and version as published coordinates
*/
override fun classLoaderIsolation() {
classLoaderIsolation("${project.group}:${project.name}:${project.version}")
classLoaderIsolation { }
}

private fun String.sanitize(): String {
return this.split(Regex("[^a-zA-Z]")).joinToString(separator = "") {
it.capitalizeFirstLetter()
}
}

/**
* Enables ClassLoader isolation.
*
* @param publishedCoordinates the coordinates of the implementation to use in the isolated classpath.
* Enables ClassLoader isolation mode using the project group, name and version as published coordinates
*/
override fun classLoaderIsolation(publishedCoordinates: String) {
this.publishedCoordinates = publishedCoordinates
override fun classLoaderIsolation(action: Action<ClassloaderIsolationSpec>) {
if (classloaderIsolationSpec == null) {
classloaderIsolationSpec = project.objects.newInstance(ClassloaderIsolationSpec::class.java)
val defaultCoordinates = "${project.group}:${project.name}:${project.version}"
classloaderIsolationSpec!!.coordinates.convention(defaultCoordinates)
classloaderIsolationSpec!!.configurationName.convention("gratatouille${defaultCoordinates.sanitize()}")
}

action.execute(classloaderIsolationSpec!!)

// See https://github.com/google/ksp/issues/1677
project.tasks.withType(AbstractArchiveTask::class.java).configureEach {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal enum class PluginVariant {
Wiring,
Tasks
}

internal fun Project.codeGeneration(action: Action<CodeGenerationSpec>, pluginVariant: PluginVariant) {
val codeGenerationSpec = DefaultCodeGenerationSpec(this)
action.execute(codeGenerationSpec)
Expand All @@ -31,7 +32,7 @@ internal fun Project.codeGeneration(action: Action<CodeGenerationSpec>, pluginVa
dependencies.add("ksp", dependencies.create("${BuildConfig.group}:gratatouille-processor"))

if (codeGenerationSpec.addDependencies.getOrElse(true)) {
val runtimes = when(pluginVariant) {
val runtimes = when (pluginVariant) {
PluginVariant.Simple -> listOf("wiring", "tasks")
PluginVariant.Wiring -> listOf("wiring")
PluginVariant.Tasks -> listOf("tasks")
Expand All @@ -41,15 +42,18 @@ internal fun Project.codeGeneration(action: Action<CodeGenerationSpec>, pluginVa
}
}

if (codeGenerationSpec.publishedCoordinates != null) {
when(pluginVariant) {
val ciSpec = codeGenerationSpec.classloaderIsolationSpec
if (ciSpec != null) {
when (pluginVariant) {
PluginVariant.Simple,
PluginVariant.Wiring -> {
error("To use classloader isolation, use the com.gradleup.gratatouille.tasks plugin")
}

PluginVariant.Tasks -> Unit
}
kspExtension.arg("implementationCoordinates", codeGenerationSpec.publishedCoordinates!!)
kspExtension.arg("implementationCoordinates", ciSpec.coordinates)
kspExtension.arg("configurationName", ciSpec.configurationName)
}
kspExtension.arg("enableKotlinxSerialization", codeGenerationSpec.enableKotlinxSerialization.orElse(false).get().toString())
}
Expand Down Expand Up @@ -81,7 +85,7 @@ internal fun Project.pluginMarker(id: String) {
"Gratatouille: the project contains multiple publications (${publications.joinToString(", ") { it.name }}). Use 'pluginMarker(String, String)' to specify the publication to use."
}
val publication = publications.single()
check (publication is MavenPublication) {
check(publication is MavenPublication) {
"Gratatouille: the publication is not an instance of MavenPublication."
}
createMarkerPublication(id, publication)
Expand Down
8 changes: 7 additions & 1 deletion gratatouille-processor/api/gratatouille-processor.api
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
public final class gratatouille/processor/GratatouilleProcessor : com/google/devtools/ksp/processing/SymbolProcessor {
public fun <init> (Lcom/google/devtools/ksp/processing/CodeGenerator;Lcom/google/devtools/ksp/processing/KSPLogger;Ljava/lang/String;Z)V
public fun <init> (Lcom/google/devtools/ksp/processing/CodeGenerator;Lcom/google/devtools/ksp/processing/KSPLogger;Lgratatouille/processor/IsolationOptions;Z)V
public fun process (Lcom/google/devtools/ksp/processing/Resolver;)Ljava/util/List;
}

Expand All @@ -8,6 +8,12 @@ public final class gratatouille/processor/GratatouilleProcessorProvider : com/go
public fun create (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Lcom/google/devtools/ksp/processing/SymbolProcessor;
}

public final class gratatouille/processor/IsolationOptions {
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
public final fun getConfigurationName ()Ljava/lang/String;
public final fun getCoordinates ()Ljava/lang/String;
}

public final class gratatouille/processor/UtilKt {
public static final fun capitalizeFirstLetter (Ljava/lang/String;)Ljava/lang/String;
public static final fun decapitalizeFirstLetter (Ljava/lang/String;)Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import java.util.Properties
class GratatouilleProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger,
private val implementationCoordinates: String?,
private val isolationOptions: IsolationOptions?,
private val enableKotlinxSerialization: Boolean,
) : SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
Expand Down Expand Up @@ -90,7 +90,7 @@ class GratatouilleProcessor(
private fun FileSpec.writeToKotlinDirectory(dependencies: Dependencies) = writeTo(codeGenerator, dependencies)
private fun FileSpec.writeToKotlinOrResourcesDirectory(dependencies: Dependencies) {
val fileSpec = this
val file = if (implementationCoordinates != null) {
val file = if (isolationOptions != null) {
codeGenerator.createNewFile(
dependencies,
"",
Expand All @@ -114,7 +114,7 @@ class GratatouilleProcessor(
when (it) {
is KSFunctionDeclaration -> {
val dependencies = it.asIsolatingDependencies()
it.toGTask(logger, implementationCoordinates, enableKotlinxSerialization).apply {
it.toGTask(logger, isolationOptions, enableKotlinxSerialization).apply {
entryPoint().writeToKotlinDirectory(dependencies)
taskFile().writeToKotlinOrResourcesDirectory(dependencies)
}
Expand All @@ -138,13 +138,24 @@ class GratatouilleProcessorProvider : SymbolProcessorProvider {
override fun create(
environment: SymbolProcessorEnvironment
): SymbolProcessor {
val coordinates = environment.options.get("implementationCoordinates")
val isolationOptions = if (coordinates != null) {
IsolationOptions(coordinates, environment.options.get("configurationName")!!)
} else {
null
}
return GratatouilleProcessor(
environment.codeGenerator,
environment.logger,
environment.options.get("implementationCoordinates"),
isolationOptions,
environment.options.get("enableKotlinxSerialization").toBoolean()
)
}
}

internal val classpathParameter = IrTaskProperty(Classpath, classpath, false, false, false)
internal val classpathParameter = IrTaskProperty(Classpath, classpath, false, false, false)

class IsolationOptions(
val coordinates: String,
val configurationName: String
)
Original file line number Diff line number Diff line change
@@ -1,53 +1,9 @@
package gratatouille.processor.codegen

import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.MemberName
import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.ParameterizedTypeName
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.buildCodeBlock
import com.squareup.kotlinpoet.withIndent
import gratatouille.processor.biConsumer
import gratatouille.processor.capitalizeFirstLetter
import gratatouille.processor.classpath
import gratatouille.processor.classpathParameter
import gratatouille.processor.decapitalizeFirstLetter
import gratatouille.processor.extraClasspath
import gratatouille.processor.gratatouilleBuildService
import gratatouille.processor.gratatouilleWiringPackageName
import gratatouille.processor.ir.Classpath
import gratatouille.processor.ir.InputDirectory
import gratatouille.processor.ir.InputFile
import gratatouille.processor.ir.InputFiles
import gratatouille.processor.ir.IrBuildServiceParameter
import gratatouille.processor.ir.IrLoggerParameter
import gratatouille.processor.ir.IrTaskPropertyParameter
import gratatouille.processor.ir.IrTask
import gratatouille.processor.ir.IrTaskProperty
import gratatouille.processor.ir.JvmType
import gratatouille.processor.ir.KotlinxSerializableInput
import gratatouille.processor.ir.KotlinxSerializableOutput
import gratatouille.processor.ir.OutputDirectory
import gratatouille.processor.ir.OutputFile
import gratatouille.processor.ir.Type
import gratatouille.processor.ir.inputs
import gratatouille.processor.ir.isInput
import gratatouille.processor.ir.iterateRunArguments
import gratatouille.processor.ir.outputs
import gratatouille.processor.ir.properties
import gratatouille.processor.taskDescription
import gratatouille.processor.taskGroup
import gratatouille.processor.taskName
import gratatouille.processor.toCodeBlock
import gratatouille.processor.workerExecutor
import gratatouille.processor.*
import gratatouille.processor.ir.*


internal fun IrTask.taskFile(): FileSpec {
Expand Down Expand Up @@ -105,21 +61,25 @@ private fun IrTask.register(): FunSpec {
}
.addCode(
buildCodeBlock {
add(
"val configuration = this@%L.configurations.detachedConfiguration()\n",
registerName(),
)
if (implementationCoordinates != null) {
add("configuration.dependencies.add(dependencies.create(%S))\n", implementationCoordinates)

if (isolationOptions != null) {
add("var configuration = this@%L.configurations.findByName(%S)\n", registerName(), isolationOptions.configurationName)
add("if (configuration == null) {\n")
withIndent {
add("configuration = this@%L.configurations.create(%S)\n", registerName(), isolationOptions.configurationName)
add("configuration.dependencies.add(dependencies.create(%S))\n", isolationOptions.coordinates)
}
add("}\n")
add(
"gradle.sharedServices.registerIfAbsent(\"gratatouille\", %T::class.java) {}\n",
ClassName(gratatouilleWiringPackageName, "GratatouilleBuildService")
)
}

add("return tasks.register(${taskName},%T::class.java) {\n", taskClassName())
withIndent {
add("it.${classpath}.from(configuration)\n")
if (isolationOptions != null) {
add("it.${classpath}.from(configuration)\n")
}
add("if (extraClasspath != null) {\n")
withIndent {
add("it.${classpath}.from(extraClasspath)\n")
Expand Down Expand Up @@ -213,7 +173,7 @@ private fun IrTask.task(): TypeSpec {
it.toPropertySpec()
)
}
if (implementationCoordinates != null) {
if (isolationOptions != null) {
addFunction(
FunSpec.builder("getGratatouilleBuildService")
.addModifiers(KModifier.ABSTRACT)
Expand Down Expand Up @@ -250,7 +210,7 @@ private fun IrTask.taskAction(): FunSpec {
buildCodeBlock {
add("${workerExecutor}().noIsolation().submit(%T::class.java) {\n", workActionClassName())
withIndent {
if (implementationCoordinates != null) {
if (isolationOptions != null) {
add("it.$gratatouilleBuildService.set(getGratatouilleBuildService())\n")
}
add("it.${classpath} = ${classpath}.files\n")
Expand Down Expand Up @@ -434,7 +394,7 @@ private fun IrTask.workActionExecute(): FunSpec {
buildCodeBlock {
add("with(parameters) {\n")
withIndent {
if (implementationCoordinates != null) {
if (isolationOptions != null) {
add("$gratatouilleBuildService.get().classloader($classpath)")
add(".loadClass(%S)\n", entryPointClassName().canonicalName)
add(".declaredMethods.single()\n")
Expand Down Expand Up @@ -524,13 +484,8 @@ private fun IrTask.workParameters(): TypeSpec {
)
}

is IrLoggerParameter -> {
Unit
}
is IrLoggerParameter -> Unit
}
}
parameters.properties.forEach {

}
returnValues.forEach {
addProperty(PropertySpec.builder(it.name, it.toTypeName()).mutable(true).build())
Expand Down
Loading