write partial kotlin dsl

This commit is contained in:
mae
2025-11-15 21:51:43 -06:00
parent 7110fdb53e
commit 98950f21f3
5 changed files with 321 additions and 1 deletions

View File

@@ -10,6 +10,10 @@ repositories {
mavenCentral()
}
val kotlinVersion = "2.2.10"
val kotlinCoroutinesVersion = "1.7.0-RC"
dependencies {
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
@@ -18,6 +22,11 @@ dependencies {
testImplementation(kotlin("test"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
implementation(kotlin("reflect"))
implementation("org.jetbrains.kotlin:kotlin-scripting-common:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-scripting-jvm:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies-maven:${kotlinVersion}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${kotlinCoroutinesVersion}")
}
kotlin {
@@ -27,4 +36,4 @@ kotlin {
tasks.test {
useJUnitPlatform()
}
project.layout.buildDirectory.set(file("../build"))
project.layout.buildDirectory.set(file("../../build"))

View File

@@ -0,0 +1,16 @@
package moe.rosa.planterette.api
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
sealed interface Capability {
val id: String
@SerialName("basic")
data class Basic(override val id: String) : Capability
@SerialName("dbus")
data class DBus(override val id: String, val own: List<String>) : Capability
}

View File

@@ -0,0 +1,36 @@
package moe.rosa.planterette.api
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class Manifest(
val metadata: Metadata,
val executable: Executable,
val capabilities: List<Capability>,
val permissions: List<Capability>
) {
@Serializable
data class Metadata(
var id: String,
var name: String,
var description: String,
var author: String,
var icon: String,
var version: Int,
@SerialName("version_name") var versionName: String
) {
constructor() : this("", "", "", "", "", -1, "")
}
@Serializable
data class Executable(
@SerialName("base_image") var baseImage: String,
var binary: String,
val args: MutableList<String>,
val env: MutableMap<String, String>
) {
constructor() : this("", "", mutableListOf(), mutableMapOf())
}
}

View File

@@ -0,0 +1,211 @@
@file:Suppress("unused")
package moe.rosa.planterette.dsl
import moe.rosa.planterette.api.Capability
import moe.rosa.planterette.api.Manifest
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@DslMarker
annotation class PlanteretteBlockMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PlanteretteBlockMarker
annotation class MetadataBlockMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PlanteretteBlockMarker
annotation class ExecutableBlockMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PlanteretteBlockMarker
annotation class CapabilitiesBlockMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@CapabilitiesBlockMarker
annotation class DBusBlockMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PlanteretteBlockMarker
annotation class PermissionsBlockMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PermissionsBlockMarker
annotation class FilesystemBlockMarker
@PlanteretteBlockMarker
data class PlanteretteBlock(
var metadata: MetadataBlock,
var executable: ExecutableBlock,
var capabilities: CapabilitiesBlock,
var permissions: PermissionsBlock
)
@MetadataBlockMarker
data class MetadataBlock(var metadata: Manifest.Metadata)
@ExecutableBlockMarker
data class ExecutableBlock(var executable: Manifest.Executable)
@CapabilitiesBlockMarker
data class CapabilitiesBlock(var capabilities: MutableList<Capability>)
// TODO add the rest of this
@DBusBlockMarker
data class DBusBlock(var own: MutableList<String>)
@PermissionsBlockMarker
data class PermissionsBlock(var permissions: MutableList<Capability>)
@FilesystemBlockMarker
class FilesystemBlock(var filesystemPermissions: MutableList<Capability>)
@PlanteretteBlockMarker
fun planterette(init: PlanteretteBlock.() -> Unit) {
PlanteretteBlock(MetadataBlock(Manifest.Metadata()), ExecutableBlock(Manifest.Executable()), CapabilitiesBlock(mutableListOf()), PermissionsBlock(mutableListOf())).apply(init)
}
@PlanteretteBlockMarker
fun PlanteretteBlock.metadata(init: @MetadataBlockMarker MetadataBlock.() -> Unit) {
this.metadata.apply(init)
}
@MetadataBlockMarker
fun MetadataBlock.id(id: String) {
this.metadata.id = id
}
@MetadataBlockMarker
fun MetadataBlock.name(name: String) {
this.metadata.name = name
}
@MetadataBlockMarker
fun MetadataBlock.description(description: String) {
this.metadata.description = description
}
@MetadataBlockMarker
fun MetadataBlock.author(author: String) {
this.metadata.author = author
}
@MetadataBlockMarker
fun MetadataBlock.icon(icon: String) {
this.metadata.icon = icon
}
@MetadataBlockMarker
fun MetadataBlock.version(number: Int, name: String) {
this.metadata.version = number
this.metadata.versionName = name
}
@PlanteretteBlockMarker
fun PlanteretteBlock.executable(init: @ExecutableBlockMarker ExecutableBlock.() -> Unit) {
this.executable.apply(init)
}
@ExecutableBlockMarker
fun ExecutableBlock.baseImage(baseImage: String) {
this.executable.baseImage = baseImage
}
@ExecutableBlockMarker
fun ExecutableBlock.binary(binary: String) {
this.executable.binary = binary
}
@ExecutableBlockMarker
fun ExecutableBlock.args(vararg args: String) {
this.executable.args.addAll(args)
}
@ExecutableBlockMarker
fun ExecutableBlock.env(vararg env: Pair<String, String>) {
this.executable.env.putAll(env)
}
@PlanteretteBlockMarker
fun PlanteretteBlock.capabilities(init: @CapabilitiesBlockMarker CapabilitiesBlock.() -> Unit) {
this.capabilities.apply(init)
}
internal fun CapabilitiesBlock.addBasic(id: String) {
this.capabilities.add(Capability.Basic(id))
}
@CapabilitiesBlockMarker
fun CapabilitiesBlock.portal() {
addBasic("moe.rosa.capabilities.Portal")
}
@CapabilitiesBlockMarker
fun CapabilitiesBlock.secrets() {
addBasic("moe.rosa.capabilities.Secrets")
}
@CapabilitiesBlockMarker
fun CapabilitiesBlock.developer() {
addBasic("moe.rosa.capabilities.Developer")
}
@CapabilitiesBlockMarker
fun CapabilitiesBlock.graphics() {
addBasic("moe.rosa.capabilities.Graphics")
}
@CapabilitiesBlockMarker
fun CapabilitiesBlock.audio() {
addBasic("moe.rosa.capabilities.Audio")
}
@CapabilitiesBlockMarker
fun CapabilitiesBlock.dbus(init: @DBusBlockMarker DBusBlock.() -> Unit) {
val dbus = DBusBlock(mutableListOf())
this.capabilities.add(Capability.DBus("moe.rosa.capabilities.DBus", dbus.own))
}
@PlanteretteBlockMarker
fun PlanteretteBlock.permissions(init: @PermissionsBlockMarker PermissionsBlock.() -> Unit) {
this.permissions.apply(init)
}
internal fun PermissionsBlock.addBasic(id: String) {
this.permissions.add(Capability.Basic(id))
}
@PermissionsBlockMarker
fun PermissionsBlock.notifications() {
addBasic("moe.rosa.permissions.Notifications")
}
@PermissionsBlockMarker
fun PermissionsBlock.filesystem(init: @FilesystemBlockMarker FilesystemBlock.() -> Unit) {
this.permissions.addAll(FilesystemBlock(mutableListOf()).apply(init).filesystemPermissions)
}
@FilesystemBlockMarker
fun FilesystemBlock.fileManager() {
this.filesystemPermissions.add(Capability.Basic("moe.rosa.permissions.filesystem.FileManager"))
}
@FilesystemBlockMarker
fun FilesystemBlock.etc() {
this.filesystemPermissions.add(Capability.Basic("moe.rosa.permissions.filesystem.Etc"))
}
@FilesystemBlockMarker
fun FilesystemBlock.tmp() {
this.filesystemPermissions.add(Capability.Basic("moe.rosa.permissions.filesystem.Tmp"))
}
@PermissionsBlockMarker
fun PermissionsBlock.network() {
addBasic("moe.rosa.permissions.Network")
}
@PermissionsBlockMarker
fun PermissionsBlock.system() {
addBasic("moe.rosa.permissions.System")
}

View File

@@ -0,0 +1,48 @@
package moe.rosa.planterette.dsl
import kotlinx.coroutines.runBlocking
import moe.rosa.planterette.api.Capability
import moe.rosa.planterette.api.Manifest
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.*
import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
import kotlin.script.experimental.jvm.jvm
@KotlinScript(
fileExtension = "plt.kts",
compilationConfiguration = ScriptWithMavenDepsConfiguration::class
)
open class PltRecipe
object ScriptWithMavenDepsConfiguration : ScriptCompilationConfiguration(
{
defaultImports(DependsOn::class, Repository::class)
defaultImports.append("moe.rosa.planterette.dsl.*")
jvm {
dependenciesFromCurrentContext(
"script",
"kotlin-scripting-dependencies"
)
}
refineConfiguration {
onAnnotations(DependsOn::class, Repository::class, handler = ::configureMavenDepsOnAnnotations)
}
}
)
private val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), MavenDependenciesResolver())
fun configureMavenDepsOnAnnotations(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> {
val annotations = context.collectedData?.get(ScriptCollectedData.collectedAnnotations)?.takeIf { it.isNotEmpty() }
?: return context.compilationConfiguration.asSuccess()
return runBlocking {
resolver.resolveFromScriptSourceAnnotations(annotations)
}.onSuccess {
context.compilationConfiguration.with {
dependencies.append(JvmDependency(it))
}.asSuccess()
}
}