Further work and debugging on plugin integration

This commit is contained in:
grimsi
2024-10-11 10:18:48 +02:00
parent bfcd3d83c9
commit cc6056fce8
12 changed files with 158 additions and 78 deletions
+9 -2
View File
@@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
allprojects { allprojects {
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
} }
} }
@@ -22,11 +23,17 @@ subprojects {
tasks.withType<KotlinJvmCompile> { tasks.withType<KotlinJvmCompile> {
compilerOptions { compilerOptions {
apiVersion = KotlinVersion.KOTLIN_2_2 languageVersion = KotlinVersion.KOTLIN_2_0
languageVersion = KotlinVersion.KOTLIN_2_2 apiVersion = KotlinVersion.KOTLIN_2_0
jvmTarget = JvmTarget.JVM_21 jvmTarget = JvmTarget.JVM_21
progressiveMode = true progressiveMode = true
freeCompilerArgs.add("-Xjsr305=strict") freeCompilerArgs.add("-Xjsr305=strict")
} }
} }
} }
tasks.named("build") {
dependsOn(":gameyfin:uberJar")
}
extra.set("pluginDir", rootProject.layout.buildDirectory.get().asFile.resolve("plugins"))
+26 -16
View File
@@ -1,4 +1,6 @@
group = "de.grimsi" group = "de.grimsi"
val pluginDir: File by rootProject.extra
val appMainClass = "de.grimsi.gameyfin.GameyfinApplication"
plugins { plugins {
id("org.springframework.boot") id("org.springframework.boot")
@@ -7,21 +9,19 @@ plugins {
kotlin("jvm") kotlin("jvm")
kotlin("plugin.spring") kotlin("plugin.spring")
kotlin("plugin.jpa") kotlin("plugin.jpa")
java application
id("com.google.devtools.ksp") version "2.0.20-1.0.24"
}
application {
mainClass.set(appMainClass)
} }
allOpen { allOpen {
annotations("javax.persistence.Entity", "javax.persistence.MappedSuperclass", "javax.persistence.Embedabble") annotations("javax.persistence.Entity", "javax.persistence.MappedSuperclass", "javax.persistence.Embedabble")
} }
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories { repositories {
mavenCentral()
maven { maven {
setUrl("https://maven.vaadin.com/vaadin-addons") setUrl("https://maven.vaadin.com/vaadin-addons")
} }
@@ -68,6 +68,7 @@ dependencies {
// Plugins // Plugins
implementation(project(":plugin-api")) implementation(project(":plugin-api"))
ksp("care.better.pf4j:pf4j-kotlin-symbol-processing:2.0.20-1.0.1")
// Development // Development
developmentOnly("org.springframework.boot:spring-boot-devtools") developmentOnly("org.springframework.boot:spring-boot-devtools")
@@ -85,16 +86,25 @@ dependencyManagement {
} }
} }
// Task to copy the bundled plugin JARs to the plugins directory tasks.named<JavaExec>("run") {
val copyPlugins by tasks.registering(Copy::class) { systemProperty("pf4j.pluginsDir", pluginDir.absolutePath)
// Directory where plugins will be copied
val pluginsDir = layout.buildDirectory.dir("plugins")
from(project(":plugins:igdb").tasks.named("jar"))
into(pluginsDir)
} }
tasks.named("compileKotlin") { tasks.register<Jar>("uberJar") {
dependsOn(copyPlugins) dependsOn(tasks.named("compileKotlin"))
archiveClassifier.set("uber")
from(sourceSets.main.get().output)
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
manifest {
attributes["Main-Class"] = appMainClass
}
archiveBaseName.set(project.name)
} }
tasks.withType<Test> { tasks.withType<Test> {
@@ -1,14 +1,25 @@
package de.grimsi.gameyfin.core package de.grimsi.gameyfin.core
import io.github.oshai.kotlinlogging.KotlinLogging
import org.pf4j.DefaultPluginManager import org.pf4j.DefaultPluginManager
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.context.event.EventListener
import java.nio.file.Path import java.nio.file.Path
@Configuration @Configuration
class PluginManagerConfig { class PluginManagerConfig {
private val log = KotlinLogging.logger {}
private val pluginPath = Path.of("plugins") private val pluginPath = Path.of("plugins")
@Bean @Bean
fun pluginManager() = DefaultPluginManager(pluginPath) fun pluginManager() = DefaultPluginManager(pluginPath)
@EventListener(ApplicationReadyEvent::class)
fun loadedPlugins() {
pluginManager().loadPlugins()
pluginManager().startPlugins()
log.info { "Loaded plugins: ${pluginManager().plugins.map { it.pluginId }}" }
}
} }
@@ -1,10 +1,8 @@
package de.grimsi.gameyfin.games package de.grimsi.gameyfin.games
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataPlugin import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataFetcher
import io.github.oshai.kotlinlogging.KotlinLogging import io.github.oshai.kotlinlogging.KotlinLogging
import org.pf4j.PluginManager import org.pf4j.PluginManager
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.event.EventListener
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import java.nio.file.Path import java.nio.file.Path
@@ -16,15 +14,8 @@ class GameService(
) { ) {
private val log = KotlinLogging.logger {} private val log = KotlinLogging.logger {}
private val metadataPlugins: List<GameMetadataPlugin> private val metadataPlugins: List<GameMetadataFetcher>
get() = pluginManager.getExtensions(GameMetadataPlugin::class.java) get() = pluginManager.getExtensions(GameMetadataFetcher::class.java)
@EventListener(ApplicationReadyEvent::class)
fun loadedPlugins() {
pluginManager.loadPlugins()
pluginManager.startPlugins()
log.info { "Loaded metadata plugins: ${metadataPlugins.map { it::class.simpleName }}" }
}
fun createOrUpdate(game: Game): Game { fun createOrUpdate(game: Game): Game {
return gameRepository.save(game) return gameRepository.save(game)
+4
View File
@@ -1,3 +1,4 @@
# Plugin versions
kotlinVersion=2.0.20 kotlinVersion=2.0.20
vaadinVersion=24.4.13 vaadinVersion=24.4.13
springBootVersion=3.3.4 springBootVersion=3.3.4
@@ -5,3 +6,6 @@ springCloudVersion=2023.0.3
springDependencyManagementVersion=1.1.6 springDependencyManagementVersion=1.1.6
pf4jVersion=3.12.0 pf4jVersion=3.12.0
pf4jSpringVersion=0.9.0 pf4jSpringVersion=0.9.0
# Annotation processor settings
kapt.use.k2=true
ksp.useKSP2=true
+2
View File
@@ -12,6 +12,8 @@ dependencies {
// PF4J (shared) // PF4J (shared)
api("org.pf4j:pf4j:${rootProject.extra["pf4jVersion"]}") api("org.pf4j:pf4j:${rootProject.extra["pf4jVersion"]}")
implementation(kotlin("stdlib"))
// Test dependencies // Test dependencies
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
} }
@@ -2,7 +2,7 @@ package de.grimsi.gameyfin.pluginapi.gamemetadata
import org.pf4j.ExtensionPoint import org.pf4j.ExtensionPoint
interface GameMetadataPlugin : ExtensionPoint { interface GameMetadataFetcher : ExtensionPoint {
fun getConfig(): Map<String, String> fun getConfig(): Map<String, String>
fun setConfig(config: Map<String, String>) fun setConfig(config: Map<String, String>)
fun fetchMetadata(gameId: String): GameMetadata fun fetchMetadata(gameId: String): GameMetadata
+55
View File
@@ -0,0 +1,55 @@
val pluginDir: File by rootProject.extra
plugins {
kotlin("jvm")
}
subprojects {
apply(plugin = "org.jetbrains.kotlin.jvm")
dependencies {
implementation(project(":plugin-api"))
}
tasks.register<Jar>("plugin") {
archiveBaseName.set("plugin-${project.name}")
// first taking the classes generated by the jar task
into("classes") {
with(tasks.named<Jar>("jar").get())
}
// and then we also need to include any libraries that are needed by the plugin
dependsOn(configurations.runtimeClasspath)
into("lib") {
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }
})
}
archiveExtension.set("jar")
}
tasks.register<Copy>("assemblePlugin") {
from(project.tasks.named("plugin"))
into(pluginDir)
}
tasks.jar {
manifest {
from("./src/main/resources/MANIFEST.MF")
}
}
tasks.named("build") {
dependsOn(tasks.named("plugin"))
}
}
tasks.register<Copy>("assemblePlugins") {
dependsOn(subprojects.map { it.tasks.named("assemblePlugin") })
}
tasks {
"build" {
dependsOn(named("assemblePlugins"))
}
}
+2 -19
View File
@@ -1,24 +1,7 @@
plugins { plugins {
kotlin("jvm") id("com.google.devtools.ksp") version "2.0.20-1.0.24"
id("kotlin-kapt")
}
group = "de.grimsi.gameyfin.plugins"
repositories {
mavenCentral()
} }
dependencies { dependencies {
implementation(project(":plugin-api")) ksp("care.better.pf4j:pf4j-kotlin-symbol-processing:2.0.20-1.0.1")
}
tasks.jar {
manifest {
from("./src/main/resources/MANIFEST.MF")
}
}
tasks.test {
useJUnitPlatform()
} }
@@ -1,35 +1,48 @@
package de.grimsi.gameyfin.plugins.igdb package de.grimsi.gameyfin.plugins.igdb
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadata import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadata
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataPlugin import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataFetcher
import org.pf4j.Extension import org.pf4j.Extension
import org.pf4j.Plugin
import org.pf4j.PluginWrapper
import java.time.Instant import java.time.Instant
@Extension class IgdbPlugin(wrapper: PluginWrapper) : Plugin(wrapper) {
class IgdbPlugin : GameMetadataPlugin {
override fun getConfig(): Map<String, String> { override fun start() {
TODO("Not yet implemented") println("IgdbPlugin.start()")
} }
override fun setConfig(config: Map<String, String>) { override fun stop() {
TODO("Not yet implemented") println("IgdbPlugin.stop()")
} }
override fun fetchMetadata(gameId: String): GameMetadata { @Extension
return GameMetadata( class IgdbMetadataFetcher : GameMetadataFetcher {
title = "Test Game", override fun getConfig(): Map<String, String> {
description = "This is a test game", TODO("Not yet implemented")
release = Instant.now(), }
userRating = 0,
criticRating = 0, override fun setConfig(config: Map<String, String>) {
developedBy = listOf("Test Developer"), TODO("Not yet implemented")
publishedBy = listOf("Test Publisher"), }
genres = listOf(),
themes = listOf(), override fun fetchMetadata(gameId: String): GameMetadata {
screenshotUrls = listOf(), return GameMetadata(
videoUrls = listOf(), title = "Test Game",
features = listOf(), description = "This is a test game",
perspectives = listOf() release = Instant.now(),
) userRating = 0,
criticRating = 0,
developedBy = listOf("Test Developer"),
publishedBy = listOf("Test Publisher"),
genres = listOf(),
themes = listOf(),
screenshotUrls = listOf(),
videoUrls = listOf(),
features = listOf(),
perspectives = listOf()
)
}
} }
} }
+1 -1
View File
@@ -1,5 +1,5 @@
Manifest-Version: 1.0 Manifest-Version: 1.0
Plugin-Id: igdb Plugin-Id: igdb
Plugin-Class: de.grimsi.gameyfin.plugins.igdb.IgdbPlugin Plugin-Class: de.grimsi.gameyfin.plugins.igdb.IgdbPlugin
Plugin-Version: 1.0.0 Plugin-Version: 1.0.0-SNAPSHOT
Plugin-Provider: grimsi Plugin-Provider: grimsi
+7 -3
View File
@@ -15,6 +15,10 @@ pluginManagement {
} }
} }
include("gameyfin")
include("plugin-api") include(":plugin-api")
include("plugins:igdb") include(":gameyfin")
include(":plugins")
include(":plugins:igdb")