392 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
			
		
		
	
	
			392 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
| package moe.rosa.planterette.dsl
 | |
| 
 | |
| import moe.rosa.planterette.PlanteretteConfig
 | |
| import moe.rosa.planterette.dsl.DSLEnablements.*
 | |
| import moe.rosa.planterette.hakurei.*
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @PlanteretteDSL
 | |
| annotation class HakureiDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @HakureiDSL
 | |
| annotation class DBusDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @HakureiDSL
 | |
| annotation class ExtraPermsDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @HakureiDSL
 | |
| annotation class ContainerDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @ContainerDSL
 | |
| annotation class FilesystemDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @FilesystemDSL
 | |
| annotation class FSBindDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @FilesystemDSL
 | |
| annotation class FSEphemeralDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @FilesystemDSL
 | |
| annotation class FSLinkDSL
 | |
| 
 | |
| @Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
 | |
| @FilesystemDSL
 | |
| annotation class FSOverlayDSL
 | |
| 
 | |
| @PlanteretteDSL
 | |
| fun PlanteretteConfig.hakurei(id: String, init: @HakureiDSL HakureiConfig.() -> Unit) {
 | |
|     this.hakurei = HakureiConfig(id).apply(init)
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.executable(path: String, vararg args: String) {
 | |
|     this.path = AbsolutePath(path)
 | |
|     this.args = args.toList()
 | |
| }
 | |
| @HakureiDSL
 | |
| enum class DSLEnablements {
 | |
|     Wayland,
 | |
|     X11,
 | |
|     DBus,
 | |
|     Pulse
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.enable(vararg enablements: DSLEnablements) {
 | |
|     val enable = Enablements(wayland = null, x11 = null, dbus = null, pulse = null)
 | |
|     enablements.map {
 | |
|         when(it) {
 | |
|             Wayland -> enable.wayland = true
 | |
|             X11 -> enable.x11 = true
 | |
|             DBus -> enable.dbus = true
 | |
|             Pulse -> enable.pulse = true
 | |
|         }
 | |
|     }
 | |
|     this.enablements = enable
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.directWayland(directWayland: Boolean = true) {
 | |
|     this.directWayland = directWayland
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.username(username: String) {
 | |
|     this.username = username
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.shell(shell: String) {
 | |
|     this.shell = AbsolutePath(shell)
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.home(home: String) {
 | |
|     this.home = AbsolutePath(home)
 | |
| }
 | |
| //TODO(mae) automatic identity?
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.identity(identity: Int? = null) {
 | |
|     this.identity = identity
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.groups(vararg groups: String) {
 | |
|     this.groups = groups.toList()
 | |
| }
 | |
| data class DBusConfigs(var session: DBusConfig? = null, var system: DBusConfig? = null)
 | |
| 
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.dbus(init: @DBusDSL DBusConfigs.() -> Unit) {
 | |
|     val dbus = DBusConfigs().apply(init)
 | |
|     this.sessionBus = dbus.session
 | |
|     this.systemBus = dbus.system
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfigs.session(init: @DBusDSL DBusConfig.() -> Unit) {
 | |
|     this.session = DBusConfig().apply(init)
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfigs.system(init: @DBusDSL DBusConfig.() -> Unit) {
 | |
|     this.system = DBusConfig().apply(init)
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.see(vararg see: String) {
 | |
|     this.see = see.toList()
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.talk(vararg talk: String) {
 | |
|     this.talk = talk.toList()
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.own(vararg own: String) {
 | |
|     this.own = own.toList()
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.call(vararg call: Pair<String, String>) {
 | |
|     this.call = call.toMap()
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.broadcast(vararg broadcast: Pair<String, String>) {
 | |
|     this.broadcast = broadcast.toMap()
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.log(log: Boolean = true) {
 | |
|     this.log = log
 | |
| }
 | |
| @DBusDSL
 | |
| fun DBusConfig.filter(filter: Boolean = true) {
 | |
|     this.filter = filter
 | |
| }
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.extraPerms(vararg extraPerms: ExtraPermsConfig) {
 | |
|     this.extraPerms = extraPerms.toList()
 | |
| }
 | |
| @ExtraPermsDSL
 | |
| fun perm(path: String, init: ExtraPermsConfig.() -> Unit): ExtraPermsConfig {
 | |
|     return ExtraPermsConfig(path = AbsolutePath(path)).apply(init)
 | |
| }
 | |
| @ExtraPermsDSL
 | |
| fun perm(path: String, ensure: Boolean? = null, rwx: String): ExtraPermsConfig {
 | |
|     if(rwx.length != 3) throw IllegalArgumentException()
 | |
|     // TODO(mae): is there a difference between null and false in this case?
 | |
|     val read: Boolean? = when(rwx[0]) {
 | |
|         'r', 'R' -> true
 | |
|         else -> null
 | |
|     }
 | |
|     val write: Boolean? = when(rwx[1]) {
 | |
|         'w', 'W' -> true
 | |
|         else -> null
 | |
|     }
 | |
|     val execute: Boolean? = when(rwx[2]) {
 | |
|         'x', 'X' -> true
 | |
|         else -> null
 | |
|     }
 | |
|     return ExtraPermsConfig(ensure, path = AbsolutePath(path), read, write, execute)
 | |
| }
 | |
| @ExtraPermsDSL
 | |
| fun ExtraPermsConfig.ensure(ensure: Boolean = true) {
 | |
|     this.ensure = ensure
 | |
| }
 | |
| @ExtraPermsDSL
 | |
| fun ExtraPermsConfig.read(read: Boolean = true) {
 | |
|     this.read = read
 | |
| }
 | |
| @ExtraPermsDSL
 | |
| fun ExtraPermsConfig.write(write: Boolean = true) {
 | |
|     this.write = write
 | |
| }
 | |
| @ExtraPermsDSL
 | |
| fun ExtraPermsConfig.execute(execute: Boolean = true) {
 | |
|     this.execute = execute
 | |
| }
 | |
| 
 | |
| @HakureiDSL
 | |
| fun HakureiConfig.container(init: @ContainerDSL ContainerConfig.() -> Unit) {
 | |
|     this.container = ContainerConfig().apply(init)
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.hostname(hostname: String) {
 | |
|     this.hostname = hostname
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.waitDelay(waitDelay: Long) {
 | |
|     this.waitDelay = waitDelay
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.noTimeout() {
 | |
|     this.waitDelay = -1
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.seccompCompat(seccompCompat: Boolean = true) {
 | |
|     this.seccompCompat = seccompCompat
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.devel(devel: Boolean = true) {
 | |
|     this.devel = devel
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.userns(userns: Boolean = true) {
 | |
|     this.userns = userns
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.hostNet(hostNet: Boolean = true) {
 | |
|     this.hostNet = hostNet
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.hostAbstract(hostAbstract: Boolean = true) {
 | |
|     this.hostAbstract = hostAbstract
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.tty(tty: Boolean = true) {
 | |
|     this.tty = tty
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.multiarch(multiarch: Boolean = true) {
 | |
|     this.multiarch = multiarch
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.env(vararg env: Pair<String, String>) {
 | |
|     this.env = env.toMap()
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.mapRealUid(mapRealUid: Boolean = true) {
 | |
|     this.mapRealUid = mapRealUid
 | |
| }
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.device(device: Boolean = true) {
 | |
|     this.device = device
 | |
| }
 | |
| 
 | |
| @FilesystemDSL
 | |
| data class FilesystemConfigs(val configs: MutableList<FilesystemConfig> = mutableListOf())
 | |
| 
 | |
| @ContainerDSL
 | |
| fun ContainerConfig.filesystem(init: @FilesystemDSL FilesystemConfigs.() -> Unit) {
 | |
|     val config = FilesystemConfigs().apply(init)
 | |
|     this.filesystem = config.configs
 | |
| }
 | |
| @FilesystemDSL
 | |
| data class DummyFSBind(var target: String? = null,
 | |
|                        var source: String? = null,
 | |
|                        var write: Boolean? = null,
 | |
|                        var device: Boolean? = null,
 | |
|                        var ensure: Boolean? = null,
 | |
|                        var optional: Boolean? = null,
 | |
|                        var special: Boolean? = null) {
 | |
|     fun build(): FSBind {
 | |
|         return FSBind(
 | |
|             target = if(target != null) { AbsolutePath(target!!) } else null,
 | |
|             source = AbsolutePath(source!!),
 | |
|             write = write,
 | |
|             device = device,
 | |
|             ensure = ensure,
 | |
|             optional = optional,
 | |
|             special = special
 | |
|         )
 | |
|     }
 | |
| }
 | |
| @FilesystemDSL
 | |
| fun FilesystemConfigs.bind(src2dst: Pair<String, String>, init: @FSBindDSL DummyFSBind.() -> Unit = {}) {
 | |
|     val fs = DummyFSBind(target = src2dst.second, source = src2dst.first)
 | |
|     fs.apply(init)
 | |
|     this.configs.add(fs.build())
 | |
| }
 | |
| @FilesystemDSL
 | |
| fun FilesystemConfigs.bind(source: String, init: @FSBindDSL DummyFSBind.() -> Unit = {}) {
 | |
|     val fs = DummyFSBind(source = source)
 | |
|     fs.apply(init)
 | |
|     this.configs.add(fs.build())
 | |
| }
 | |
| @FSBindDSL
 | |
| fun DummyFSBind.write(write: Boolean? = true) {
 | |
|     this.write = write
 | |
| }
 | |
| @FSBindDSL
 | |
| fun DummyFSBind.device(device: Boolean? = true) {
 | |
|     this.device = device
 | |
| }
 | |
| @FSBindDSL
 | |
| fun DummyFSBind.ensure(ensure: Boolean? = true) {
 | |
|     this.ensure = ensure
 | |
| }
 | |
| @FSBindDSL
 | |
| fun DummyFSBind.optional(optional: Boolean? = true) {
 | |
|     this.optional = optional
 | |
| }
 | |
| @FSBindDSL
 | |
| fun DummyFSBind.special(special: Boolean? = true) {
 | |
|     this.special = special
 | |
| }
 | |
| @FilesystemDSL
 | |
| data class DummyFSEphemeral(val target: String? = null,
 | |
|                             var write: Boolean? = null,
 | |
|                             var size: Int? = null,
 | |
|                             var perm: Int? = null) {
 | |
|     fun build(): FSEphemeral {
 | |
|         return FSEphemeral(
 | |
|             target = AbsolutePath(target!!),
 | |
|             write = write!!,
 | |
|             size = size,
 | |
|             perm = perm!!
 | |
|         )
 | |
|     }
 | |
| }
 | |
| @FSEphemeralDSL
 | |
| fun DummyFSEphemeral.write(write: Boolean = true) {
 | |
|     this.write = write
 | |
| }
 | |
| @FSEphemeralDSL
 | |
| fun DummyFSEphemeral.size(size: Int) {
 | |
|     this.size = size
 | |
| }
 | |
| @FSEphemeralDSL
 | |
| fun DummyFSEphemeral.perm(perm: Int) {
 | |
|     this.perm = perm
 | |
| }
 | |
| @FilesystemDSL
 | |
| fun FilesystemConfigs.ephemeral(target: String, init: @FSEphemeralDSL DummyFSEphemeral.() -> Unit = {}) {
 | |
|     val fs = DummyFSEphemeral(target = target)
 | |
|     fs.apply(init)
 | |
|     this.configs.add(fs.build())
 | |
| }
 | |
| @FilesystemDSL
 | |
| data class DummyFSLink(val target: String? = null,
 | |
|                        val linkname: String? = null,
 | |
|                        var dereference: Boolean? = null) {
 | |
|     fun build(): FSLink {
 | |
|         return FSLink(
 | |
|             target = AbsolutePath(target!!),
 | |
|             linkname = linkname!!,
 | |
|             dereference = dereference!!
 | |
|         )
 | |
|     }
 | |
| }
 | |
| @FSLinkDSL
 | |
| fun DummyFSLink.dereference(dereference: Boolean = true) {
 | |
|     this.dereference = dereference
 | |
| }
 | |
| @FilesystemDSL
 | |
| fun FilesystemConfigs.link(lnk2dst: Pair<String, String>, init: @FSLinkDSL DummyFSLink.() -> Unit = {}) {
 | |
|     val fs = DummyFSLink(target = lnk2dst.second, linkname = lnk2dst.first)
 | |
|     fs.apply(init)
 | |
|     this.configs.add(fs.build())
 | |
| }
 | |
| @FilesystemDSL
 | |
| fun FilesystemConfigs.link(target: String, init: @FSLinkDSL DummyFSLink.() -> Unit = {}) {
 | |
|     val fs = DummyFSLink(target = target, linkname = target)
 | |
|     fs.apply(init)
 | |
|     this.configs.add(fs.build())
 | |
| }
 | |
| @FilesystemDSL
 | |
| data class DummyFSOverlay(val target: String? = null,
 | |
|                           var lower: MutableList<String>? = mutableListOf(),
 | |
|                           var upper: String? = null,
 | |
|                           var work: String? = null) {
 | |
|     fun build(): FSOverlay {
 | |
|         return FSOverlay(
 | |
|             target = AbsolutePath(target!!),
 | |
|             lower = lower!!.map { AbsolutePath(it)},
 | |
|             upper = AbsolutePath(upper!!),
 | |
|             work = AbsolutePath(work!!)
 | |
|         )
 | |
|     }
 | |
| }
 | |
| @FilesystemDSL
 | |
| fun FilesystemConfigs.overlay(target: String, init: @FSOverlayDSL DummyFSOverlay.() -> Unit = {}) {
 | |
|     val fs = DummyFSOverlay(target = target)
 | |
|     fs.apply(init)
 | |
|     this.configs.add(fs.build())
 | |
| }
 | |
| @FSOverlayDSL
 | |
| fun DummyFSOverlay.lower(vararg lower: String) {
 | |
|     this.lower!!.addAll(lower.toList())
 | |
| }
 | |
| @FSOverlayDSL
 | |
| fun DummyFSOverlay.upper(upper: String) {
 | |
|     this.upper = upper
 | |
| }
 | |
| @FSOverlayDSL
 | |
| fun DummyFSOverlay.work(work: String) {
 | |
|     this.work = work
 | |
| } |