From 886351c1ae6ea8142875b3f1eec0e0fc1e14bd04 Mon Sep 17 00:00:00 2001 From: Minecrell Date: Fri, 30 Apr 2021 18:43:17 +0200 Subject: [PATCH] Fixup incremental builds Get rid of all the Serializable mess and instead use @ Nested to tell Gradle to look at the plugin descriptions directly. This means that we need some annotation mess inside the plugin description classes though. :D --- .../pluginyml/GeneratePluginDescription.kt | 35 +++++++-- .../net/minecrell/pluginyml/PlatformPlugin.kt | 17 ++--- .../minecrell/pluginyml/PluginDescription.kt | 27 +++++++ .../bukkit/BukkitPluginDescription.kt | 71 +++++++++--------- .../bungee/BungeePluginDescription.kt | 20 ++--- .../pluginyml/nukkit/NukkitPlugin.kt | 2 +- .../nukkit/NukkitPluginDescription.kt | 73 ++++++++----------- 7 files changed, 139 insertions(+), 106 deletions(-) create mode 100644 src/main/kotlin/net/minecrell/pluginyml/PluginDescription.kt diff --git a/src/main/kotlin/net/minecrell/pluginyml/GeneratePluginDescription.kt b/src/main/kotlin/net/minecrell/pluginyml/GeneratePluginDescription.kt index 672e3e6..8cf9cd9 100644 --- a/src/main/kotlin/net/minecrell/pluginyml/GeneratePluginDescription.kt +++ b/src/main/kotlin/net/minecrell/pluginyml/GeneratePluginDescription.kt @@ -26,26 +26,34 @@ package net.minecrell.pluginyml import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer +import com.fasterxml.jackson.databind.util.Converter +import com.fasterxml.jackson.databind.util.StdConverter import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator import com.fasterxml.jackson.module.kotlin.registerKotlinModule import org.gradle.api.DefaultTask +import org.gradle.api.NamedDomainObjectCollection +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.property import java.io.File -import java.io.Serializable open class GeneratePluginDescription : DefaultTask() { @Input - var fileName: String? = null + val fileName: Property = project.objects.property() - @Input - var pluginDescription: Serializable? = null + @Nested + val pluginDescription: Property = project.objects.property() - val outputFile: File - @OutputFile get() = File(temporaryDir, fileName) + val outputFile: Provider + @OutputFile get() = fileName.map { File(temporaryDir, it) } @TaskAction fun generate() { @@ -54,11 +62,24 @@ open class GeneratePluginDescription : DefaultTask() { .enable(YAMLGenerator.Feature.MINIMIZE_QUOTES) .enable(YAMLGenerator.Feature.INDENT_ARRAYS) + val module = SimpleModule() + @Suppress("UNCHECKED_CAST") // Too stupid to figure out the generics here... + module.addSerializer(StdDelegatingSerializer(NamedDomainObjectCollection::class.java, + NamedDomainObjectCollectionConverter as Converter, *>)) + val mapper = ObjectMapper(factory) .registerKotlinModule() + .registerModule(module) .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - mapper.writeValue(outputFile, pluginDescription) + mapper.writeValue(outputFile.get(), pluginDescription.get()) + } + + object NamedDomainObjectCollectionConverter : StdConverter, Map>() { + override fun convert(value: NamedDomainObjectCollection): Map { + val namer = value.namer + return value.associateBy { namer.determineName(it) } + } } } diff --git a/src/main/kotlin/net/minecrell/pluginyml/PlatformPlugin.kt b/src/main/kotlin/net/minecrell/pluginyml/PlatformPlugin.kt index fbff9ba..f5913c3 100644 --- a/src/main/kotlin/net/minecrell/pluginyml/PlatformPlugin.kt +++ b/src/main/kotlin/net/minecrell/pluginyml/PlatformPlugin.kt @@ -31,9 +31,8 @@ import org.gradle.api.tasks.AbstractCopyTask import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.withType -import java.io.Serializable -abstract class PlatformPlugin(private val platformName: String, private val fileName: String) : Plugin { +abstract class PlatformPlugin(private val platformName: String, private val fileName: String) : Plugin { protected abstract fun createExtension(project: Project): T @@ -46,11 +45,14 @@ abstract class PlatformPlugin(private val platformName: String // Create task val generateTask = tasks.register("generate${platformName}PluginDescription") { - fileName = this@PlatformPlugin.fileName - pluginDescription = description + fileName.set(this@PlatformPlugin.fileName) + pluginDescription.set(provider { + setDefaults(project, description) + description + }) doFirst { - prepare(project, description) + validate(description) } } @@ -62,11 +64,6 @@ abstract class PlatformPlugin(private val platformName: String } } - private fun prepare(project: Project, description: T) { - setDefaults(project, description) - validate(description) - } - protected abstract fun setDefaults(project: Project, description: T) protected abstract fun validate(description: T) diff --git a/src/main/kotlin/net/minecrell/pluginyml/PluginDescription.kt b/src/main/kotlin/net/minecrell/pluginyml/PluginDescription.kt new file mode 100644 index 0000000..42040b4 --- /dev/null +++ b/src/main/kotlin/net/minecrell/pluginyml/PluginDescription.kt @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Minecrell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.minecrell.pluginyml + +interface PluginDescription diff --git a/src/main/kotlin/net/minecrell/pluginyml/bukkit/BukkitPluginDescription.kt b/src/main/kotlin/net/minecrell/pluginyml/bukkit/BukkitPluginDescription.kt index abeef44..f772892 100644 --- a/src/main/kotlin/net/minecrell/pluginyml/bukkit/BukkitPluginDescription.kt +++ b/src/main/kotlin/net/minecrell/pluginyml/bukkit/BukkitPluginDescription.kt @@ -27,37 +27,34 @@ package net.minecrell.pluginyml.bukkit import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonProperty import groovy.lang.Closure +import net.minecrell.pluginyml.PluginDescription import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project -import java.io.Serializable +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.Optional -class BukkitPluginDescription(project: Project) : Serializable { +class BukkitPluginDescription(project: Project) : PluginDescription { - @JsonProperty("api-version") var apiVersion: String? = null - var name: String? = null - var version: String? = null - var main: String? = null - var description: String? = null - var load: PluginLoadOrder? = null - var author: String? = null - var authors: List? = null - var website: String? = null - var depend: List? = null - @JsonProperty("softdepend") var softDepend: List? = null - @JsonProperty("loadbefore") var loadBefore: List? = null - var prefix: String? = null - @JsonProperty("default-permission") var defaultPermission: Permission.Default? = null - var provides: List? = null + @Input @Optional @JsonProperty("api-version") var apiVersion: String? = null + @Input var name: String? = null + @Input var version: String? = null + @Input var main: String? = null + @Input @Optional var description: String? = null + @Input @Optional var load: PluginLoadOrder? = null + @Input @Optional var author: String? = null + @Input @Optional var authors: List? = null + @Input @Optional var website: String? = null + @Input @Optional var depend: List? = null + @Input @Optional @JsonProperty("softdepend") var softDepend: List? = null + @Input @Optional @JsonProperty("loadbefore") var loadBefore: List? = null + @Input @Optional var prefix: String? = null + @Input @Optional @JsonProperty("default-permission") var defaultPermission: Permission.Default? = null + @Input @Optional var provides: List? = null - // DSL provider for commands and permissions (not serialized) - @Transient @JsonIgnore val commands: NamedDomainObjectContainer = project.container(Command::class.java) - @Transient @JsonIgnore val permissions: NamedDomainObjectContainer = project.container(Permission::class.java) - - // Java/Jackson serialization for commands and permissions - internal val commandMap: Map - @JsonProperty("commands") get() = commands.associateBy { it.name } - internal val permissionMap: Map - @JsonProperty("permissions") get() = permissions.associateBy { it.name } + @Nested val commands: NamedDomainObjectContainer = project.container(Command::class.java) + @Nested val permissions: NamedDomainObjectContainer = project.container(Permission::class.java) // For Groovy DSL fun commands(closure: Closure) = commands.configure(closure) @@ -68,23 +65,23 @@ class BukkitPluginDescription(project: Project) : Serializable { POSTWORLD } - data class Command(@Transient @JsonIgnore val name: String) : Serializable { - var description: String? = null - var aliases: List? = null - var permission: String? = null - @JsonProperty("permission-message") var permissionMessage: String? = null - var usage: String? = null + data class Command(@Input @JsonIgnore val name: String) { + @Input @Optional var description: String? = null + @Input @Optional var aliases: List? = null + @Input @Optional var permission: String? = null + @Input @Optional @JsonProperty("permission-message") var permissionMessage: String? = null + @Input @Optional var usage: String? = null } - data class Permission(@Transient @JsonIgnore val name: String) : Serializable { - var description: String? = null - var default: Default? = null + data class Permission(@Input @JsonIgnore val name: String) { + @Input @Optional var description: String? = null + @Input @Optional var default: Default? = null var children: List? - @JsonIgnore get() = childrenMap?.filterValues { it }?.keys?.toList() + @Internal @JsonIgnore get() = childrenMap?.filterValues { it }?.keys?.toList() set(value) { childrenMap = value?.associateWith { true } } - @JsonProperty("children") var childrenMap: Map? = null + @Input @Optional @JsonProperty("children") var childrenMap: Map? = null enum class Default { @JsonProperty("true") TRUE, diff --git a/src/main/kotlin/net/minecrell/pluginyml/bungee/BungeePluginDescription.kt b/src/main/kotlin/net/minecrell/pluginyml/bungee/BungeePluginDescription.kt index 21803d9..f53bd05 100644 --- a/src/main/kotlin/net/minecrell/pluginyml/bungee/BungeePluginDescription.kt +++ b/src/main/kotlin/net/minecrell/pluginyml/bungee/BungeePluginDescription.kt @@ -24,14 +24,16 @@ package net.minecrell.pluginyml.bungee -import java.io.Serializable +import net.minecrell.pluginyml.PluginDescription +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional -class BungeePluginDescription : Serializable { - var name: String? = null - var main: String? = null - var version: String? = null - var author: String? = null - var depends: Set? = null - var softDepends: Set? = null - var description: String? = null +class BungeePluginDescription : PluginDescription { + @Input var name: String? = null + @Input var main: String? = null + @Input @Optional var version: String? = null + @Input @Optional var author: String? = null + @Input @Optional var depends: Set? = null + @Input @Optional var softDepends: Set? = null + @Input @Optional var description: String? = null } diff --git a/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPlugin.kt b/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPlugin.kt index dcb435c..f235d30 100644 --- a/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPlugin.kt +++ b/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPlugin.kt @@ -47,7 +47,7 @@ class NukkitPlugin : PlatformPlugin("Nukkit", "nukkit.y if (main.isEmpty()) throw InvalidPluginDescriptionException("Main class cannot be empty") if (main.startsWith("cn.nukkit.")) throw InvalidPluginDescriptionException("Main class cannot be within cn.nukkit. package") - if (description.api?.isEmpty() != false) throw InvalidPluginDescriptionException("Nukkit API version is not set") + if (description.api.isNullOrEmpty()) throw InvalidPluginDescriptionException("Nukkit API version is not set") for (command in description.commands) { if (command.name.contains(':')) throw InvalidPluginDescriptionException("Command '${command.name}' cannot contain ':'") diff --git a/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPluginDescription.kt b/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPluginDescription.kt index 911c0cf..1b91dab 100644 --- a/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPluginDescription.kt +++ b/src/main/kotlin/net/minecrell/pluginyml/nukkit/NukkitPluginDescription.kt @@ -27,40 +27,35 @@ package net.minecrell.pluginyml.nukkit import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonProperty import groovy.lang.Closure +import net.minecrell.pluginyml.PluginDescription import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project -import java.io.Serializable +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.Optional -class NukkitPluginDescription(project: Project) : Serializable { +class NukkitPluginDescription(project: Project) : PluginDescription { - var name: String? = null - var main: String? = null - var version: String? = null - var api: List? = null - var description: String? = null - var load: PluginLoadOrder? = null - var author: String? = null - var authors: List? = null - var website: String? = null - var depend: List? = null - @JsonProperty("softdepend") var softDepend: List? = null - @JsonProperty("loadbefore") var loadBefore: List? = null - var prefix: String? = null + @Input var name: String? = null + @Input var main: String? = null + @Input var version: String? = null + @Input var api: List? = null + @Input @Optional var description: String? = null + @Input @Optional var load: PluginLoadOrder? = null + @Input @Optional var author: String? = null + @Input @Optional var authors: List? = null + @Input @Optional var website: String? = null + @Input @Optional var depend: List? = null + @Input @Optional @JsonProperty("softdepend") var softDepend: List? = null + @Input @Optional @JsonProperty("loadbefore") var loadBefore: List? = null + @Input @Optional var prefix: String? = null - // DSL provider for commands and permissions (not serialized) - @Transient @JsonIgnore - val commands: NamedDomainObjectContainer = project.container(Command::class.java) - @Transient @JsonIgnore - val permissions: NamedDomainObjectContainer = project.container(Permission::class.java) { + @Nested val commands: NamedDomainObjectContainer = project.container(Command::class.java) + @Nested val permissions: NamedDomainObjectContainer = project.container(Permission::class.java) { Permission(project, it) } - // Java/Jackson serialization for commands and permissions - internal val commandMap: Map - @JsonProperty("commands") get() = commands.associateBy { it.name } - internal val permissionMap: Map - @JsonProperty("permissions") get() = permissions.associateBy { it.name } - // For Groovy DSL fun commands(closure: Closure) = commands.configure(closure) fun permissions(closure: Closure) = permissions.configure(closure) @@ -70,29 +65,23 @@ class NukkitPluginDescription(project: Project) : Serializable { POSTWORLD } - data class Command(@Transient @JsonIgnore val name: String) : Serializable { - var description: String? = null - var aliases: List? = null - var permission: String? = null - @JsonProperty("permission-message") var permissionMessage: String? = null - var usage: String? = null + data class Command(@Input @JsonIgnore val name: String) { + @Input @Optional var description: String? = null + @Input @Optional var aliases: List? = null + @Input @Optional var permission: String? = null + @Input @Optional @JsonProperty("permission-message") var permissionMessage: String? = null + @Input @Optional var usage: String? = null } - data class Permission(@Transient @JsonIgnore val project: Project, @Transient @JsonIgnore val name: String) : Serializable { + data class Permission(@Internal @JsonIgnore val project: Project, @Input @JsonIgnore val name: String) { - var description: String? = null - var default: Default? = null + @Input @Optional var description: String? = null + @Input @Optional var default: Default? = null - // DSL provider for recursive children (not serialized) - @Transient @JsonIgnore - val children: NamedDomainObjectContainer = project.container(Permission::class.java) { + @Nested val children: NamedDomainObjectContainer = project.container(Permission::class.java) { Permission(project, it) } - // Java/Jackson serialization for commands and permissions - internal val childrenMap: Map - @JsonProperty("children") get() = children.associateBy { it.name } - // For Groovy DSL fun children(closure: Closure) = children.configure(closure)