delete outdated kotlin source
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
package moe.rosa.planterette
|
|
||||||
|
|
||||||
import moe.rosa.planterette.hakurei.HakureiConfig
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a Planterette build configuration.
|
|
||||||
* @param hakurei Hakurei container configuration for the application.
|
|
||||||
*/
|
|
||||||
data class PlanteretteConfig(var hakurei: HakureiConfig?)
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package moe.rosa.planterette.dsl
|
|
||||||
|
|
||||||
import moe.rosa.planterette.PlanteretteConfig
|
|
||||||
|
|
||||||
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
|
|
||||||
@DslMarker
|
|
||||||
annotation class PlanteretteDSL
|
|
||||||
|
|
||||||
@PlanteretteDSL
|
|
||||||
fun planterette(init: PlanteretteConfig.() -> Unit): PlanteretteConfig {
|
|
||||||
return PlanteretteConfig(hakurei = null).apply(init)
|
|
||||||
}
|
|
||||||
@@ -1,393 +0,0 @@
|
|||||||
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
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
//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
|
|
||||||
}
|
|
||||||
@ContainerDSL
|
|
||||||
fun ContainerConfig.username(username: String) {
|
|
||||||
this.username = username
|
|
||||||
}
|
|
||||||
@ContainerDSL
|
|
||||||
fun ContainerConfig.shell(shell: String) {
|
|
||||||
this.shell = AbsolutePath(shell)
|
|
||||||
}
|
|
||||||
@ContainerDSL
|
|
||||||
fun ContainerConfig.home(home: String) {
|
|
||||||
this.home = AbsolutePath(home)
|
|
||||||
}
|
|
||||||
@ContainerDSL
|
|
||||||
fun ContainerConfig.executable(path: String, vararg args: String) {
|
|
||||||
this.path = AbsolutePath(path)
|
|
||||||
this.args = args.toList()
|
|
||||||
}
|
|
||||||
@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
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package moe.rosa.planterette.dsl
|
|
||||||
|
|
||||||
import moe.rosa.planterette.PlanteretteConfig
|
|
||||||
|
|
||||||
@PlanteretteDSL
|
|
||||||
fun PlanteretteConfig.metadata() {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
package moe.rosa.planterette.hakurei
|
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
|
||||||
import kotlinx.serialization.descriptors.*
|
|
||||||
import kotlinx.serialization.encoding.*
|
|
||||||
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to the file system root.
|
|
||||||
*/
|
|
||||||
val ROOT = AbsolutePath("/")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to the directory for system-specific configuration.
|
|
||||||
*/
|
|
||||||
val ETC = AbsolutePath("/etc")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to the place for small temporary files.
|
|
||||||
*/
|
|
||||||
val TMP = AbsolutePath("/tmp")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to a "tmpfs" file system for system packages to place runtime data, socket files, and similar.
|
|
||||||
*/
|
|
||||||
val RUN = AbsolutePath("/run")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to a directory containing per-user runtime directories,
|
|
||||||
* each usually individually mounted "tmpfs" instances.
|
|
||||||
*/
|
|
||||||
val RUN_USER: AbsolutePath = RUN + "user/"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to persistent, variable system data. Writable during normal system operation.
|
|
||||||
*/
|
|
||||||
val VAR = AbsolutePath("/var/")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to persistent system data.
|
|
||||||
*/
|
|
||||||
val VAR_LIB: AbsolutePath = VAR + "lib/"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to a nonstandard directory that is usually empty.
|
|
||||||
*/
|
|
||||||
val VAR_EMPTY: AbsolutePath = VAR + "empty/"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to the root directory for device nodes.
|
|
||||||
*/
|
|
||||||
val DEV = AbsolutePath("/dev/")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to a virtual kernel file system exposing the process list and other functionality.
|
|
||||||
*/
|
|
||||||
val PROC = AbsolutePath("/proc/")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to a hierarchy below `/proc/` that exposes a number of kernel tunables.
|
|
||||||
*/
|
|
||||||
val PROC_SYS: AbsolutePath = PROC + "sys/"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Points to a virtual kernel file system exposing discovered devices and other functionality.
|
|
||||||
*/
|
|
||||||
val SYS = AbsolutePath("/sys")
|
|
||||||
/**
|
|
||||||
* Holds a pathname checked to be absolute.
|
|
||||||
* @constructor checks pathname and returns a new [AbsolutePath] if pathname is absolute.
|
|
||||||
*/
|
|
||||||
@Serializable(with = AbsolutePathSerializer::class)
|
|
||||||
data class AbsolutePath(val pathname: String, @Transient val path: Path = Path.of(pathname)) {
|
|
||||||
init {
|
|
||||||
if(!isAbsolute(pathname)) {
|
|
||||||
throw AbsolutePathException(pathname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//TODO discuss if we should keep this operator overloading around, i think it makes things cleaner but ik ozy doesn't like operator overloading
|
|
||||||
operator fun plus(other: String): AbsolutePath {
|
|
||||||
return AbsolutePath(pathname + other)
|
|
||||||
}
|
|
||||||
operator fun plus(other: AbsolutePath): AbsolutePath {
|
|
||||||
return AbsolutePath(pathname + other.pathname)
|
|
||||||
}
|
|
||||||
companion object {
|
|
||||||
fun isAbsolute(pathname: String): Boolean {
|
|
||||||
return Path.of(pathname).isAbsolute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
object AbsolutePathSerializer : KSerializer<AbsolutePath> {
|
|
||||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(this::class.qualifiedName!!, PrimitiveKind.STRING)
|
|
||||||
override fun serialize(encoder: Encoder, value: AbsolutePath) {
|
|
||||||
encoder.encodeString(value.pathname)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): AbsolutePath {
|
|
||||||
val path = decoder.decodeString()
|
|
||||||
return AbsolutePath(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returned by [AbsolutePath()] and holds the invalid pathname.
|
|
||||||
*/
|
|
||||||
data class AbsolutePathException(val pathname: String) : IllegalArgumentException("Path $pathname is not absolute")
|
|
||||||
|
|
||||||
@Serializable sealed interface FilesystemConfig
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a host to container bind mount.
|
|
||||||
* @param target mount point in container, same as source if empty
|
|
||||||
* @param source host filesystem path to make available to the container
|
|
||||||
* @param write do not mount target read only
|
|
||||||
* @param device do not disable device files on target, implies write
|
|
||||||
* @param ensure create source as a directory if it does not exist
|
|
||||||
* @param optional skip this mount point if source does not exist
|
|
||||||
* @param special enable special behavior:
|
|
||||||
* for autoroot, target must be set to [Filesystem.ROOT];
|
|
||||||
* for autoetc, target must be set to [Filesystem.ETC]
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("bind")
|
|
||||||
data class FSBind(
|
|
||||||
@SerialName("dst") val target: AbsolutePath? = null,
|
|
||||||
@SerialName("src") val source: AbsolutePath,
|
|
||||||
val write: Boolean? = null,
|
|
||||||
@SerialName("dev") val device: Boolean? = null,
|
|
||||||
val ensure: Boolean? = null,
|
|
||||||
val optional: Boolean? = null,
|
|
||||||
val special: Boolean? = null,
|
|
||||||
) : FilesystemConfig
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an ephemeral (temporary) container mount point.
|
|
||||||
* @param target mount point in container
|
|
||||||
* @param write do not mount filesystem read-only
|
|
||||||
* @param size upper limit on the size of the filesystem
|
|
||||||
* @param perm initial permission bits of the new filesystem
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("ephemeral")
|
|
||||||
data class FSEphemeral(
|
|
||||||
@SerialName("dst") val target: AbsolutePath,
|
|
||||||
val write: Boolean,
|
|
||||||
val size: Int? = null,
|
|
||||||
val perm: Int,
|
|
||||||
) : FilesystemConfig
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a symlink in the container filesystem.
|
|
||||||
* @param target link path in container
|
|
||||||
* @param linkname linkname the symlink points to
|
|
||||||
* @param dereference whether to dereference linkname before creating the link
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("link")
|
|
||||||
data class FSLink(
|
|
||||||
@SerialName("dst") val target: AbsolutePath,
|
|
||||||
val linkname: String,
|
|
||||||
val dereference: Boolean,
|
|
||||||
) : FilesystemConfig
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an overlay mount point.
|
|
||||||
* @param target mount point in container
|
|
||||||
* @param lower any filesystem, does not need to be on a writable filesystem
|
|
||||||
* @param upper the upperdir is normally on a writable filesystem, leave as null to mount Lower readonly
|
|
||||||
* @param work the workdir needs to be an empty directory on the same filesystem as `upper`, must not be null if `upper` is populated
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("overlay")
|
|
||||||
data class FSOverlay(
|
|
||||||
@SerialName("dst") val target: AbsolutePath,
|
|
||||||
val lower: List<AbsolutePath>,
|
|
||||||
val upper: AbsolutePath? = null,
|
|
||||||
val work: AbsolutePath? = null,
|
|
||||||
) : FilesystemConfig
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package moe.rosa.planterette.hakurei
|
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
val WAIT_DELAY_DEFAULT = Duration.ofSeconds(1)!!
|
|
||||||
val WAIT_DELAY_MAX = Duration.ofSeconds(30)!!
|
|
||||||
|
|
||||||
const val IDENTITY_MIN = 0
|
|
||||||
const val IDENTITY_MAX = 9999
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [HakureiConfig] configures an application container.
|
|
||||||
* @param id Reverse-DNS style configured arbitrary identifier string.
|
|
||||||
* Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
|
|
||||||
* @param enablements System services to make available in the container.
|
|
||||||
* @param sessionBus Session D-Bus proxy configuration.
|
|
||||||
* If set to null, session bus proxy assume built-in defaults.
|
|
||||||
* @param systemBus System D-Bus proxy configuration.
|
|
||||||
* If set to nil, system bus proxy is disabled.
|
|
||||||
* @param directWayland Direct access to wayland socket, no attempt is made to attach security-context-v1
|
|
||||||
* and the bare socket is made available to the container.
|
|
||||||
* @param extraPerms Extra acl update ops to perform before setuid.
|
|
||||||
* @param identity Numerical application id, passed to hsu, used to derive init user namespace credentials.
|
|
||||||
* @param groups Init user namespace supplementary groups inherited by all container processes.
|
|
||||||
* @param container High level container configuration.
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
data class HakureiConfig(
|
|
||||||
var id: String? = null,
|
|
||||||
|
|
||||||
var enablements: Enablements? = null,
|
|
||||||
@SerialName("session_bus") var sessionBus: DBusConfig? = null,
|
|
||||||
@SerialName("system_bus") var systemBus: DBusConfig? = null,
|
|
||||||
@SerialName("direct_wayland") var directWayland: Boolean? = null,
|
|
||||||
|
|
||||||
@SerialName("extra_perms") var extraPerms: List<ExtraPermsConfig>? = null,
|
|
||||||
var identity: Int? = null,
|
|
||||||
var groups: List<String>? = null,
|
|
||||||
|
|
||||||
var container: ContainerConfig? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes the container configuration to be applied to the container.
|
|
||||||
* @param hostname Container UTS namespace hostname.
|
|
||||||
* @param waitDelay Duration in nanoseconds to wait for after interrupting the initial process.
|
|
||||||
* Defaults to [WAIT_DELAY_DEFAULT] if less than or equals to zero,
|
|
||||||
* or [WAIT_DELAY_MAX] if greater than [WAIT_DELAY_MAX].
|
|
||||||
*
|
|
||||||
* @param seccompCompat Emit Flatpak-compatible seccomp filter programs.
|
|
||||||
* @param devel Allow ptrace and friends.
|
|
||||||
* @param userns Allow userns creation and container setup syscalls.
|
|
||||||
* @param hostNet Share host net namespace.
|
|
||||||
* @param hostAbstract Share abstract unix socket scope.
|
|
||||||
* @param tty Allow dangerous terminal I/O (faking input).
|
|
||||||
* @param multiarch Allow multiarch.
|
|
||||||
*
|
|
||||||
* @param env Initial process environment variables.
|
|
||||||
*
|
|
||||||
* @param mapRealUid Map target user uid to privileged user uid in the container user namespace.
|
|
||||||
* Some programs fail to connect to dbus session running as a different uid,
|
|
||||||
* this option works around it by mapping priv-side caller uid in container.
|
|
||||||
*
|
|
||||||
* @param device Mount `/dev/` from the init mount namespace as-is in the container mount namespace.
|
|
||||||
* @param filesystem Container mount points.
|
|
||||||
* If the first element targets /, it is inserted early and excluded from path hiding.
|
|
||||||
* @param username String used as the username of the emulated user, validated against the default `NAME_REGEX` from adduser.
|
|
||||||
* @param shell Pathname of shell in the container filesystem to use for the emulated user.
|
|
||||||
* @param home Directory in the container filesystem to enter and use as the home directory of the emulated user.
|
|
||||||
* @param path Pathname to executable file in the container filesystem.
|
|
||||||
* @param args Final args passed to the initial program.
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
data class ContainerConfig(
|
|
||||||
var hostname: String? = null,
|
|
||||||
@SerialName("wait_delay") var waitDelay: Long? = null,
|
|
||||||
@SerialName("seccomp_compat") var seccompCompat: Boolean? = null,
|
|
||||||
var devel: Boolean? = null,
|
|
||||||
var userns: Boolean? = null,
|
|
||||||
@SerialName("host_net") var hostNet: Boolean? = null,
|
|
||||||
@SerialName("host_abstract") var hostAbstract: Boolean? = null,
|
|
||||||
var tty: Boolean? = null,
|
|
||||||
var multiarch: Boolean? = null,
|
|
||||||
|
|
||||||
var env: Map<String, String>? = null,
|
|
||||||
|
|
||||||
@SerialName("map_real_uid") var mapRealUid: Boolean? = null,
|
|
||||||
var device: Boolean? = null,
|
|
||||||
|
|
||||||
var filesystem: List<FilesystemConfig>? = null,
|
|
||||||
|
|
||||||
var username: String? = "chronos",
|
|
||||||
var shell: AbsolutePath? = null,
|
|
||||||
var home: AbsolutePath? = null,
|
|
||||||
var path: AbsolutePath? = null,
|
|
||||||
var args: List<String>? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes an acl update op.
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
data class ExtraPermsConfig(
|
|
||||||
var ensure: Boolean? = null,
|
|
||||||
var path: AbsolutePath,
|
|
||||||
@SerialName("r") var read: Boolean? = null,
|
|
||||||
@SerialName("w") var write: Boolean? = null,
|
|
||||||
@SerialName("x") var execute: Boolean? = null,
|
|
||||||
) {
|
|
||||||
override fun toString(): String {
|
|
||||||
val buffer = StringBuffer(5 + path.toString().length)
|
|
||||||
buffer.append("---")
|
|
||||||
if(ensure == true) {
|
|
||||||
buffer.append("+")
|
|
||||||
}
|
|
||||||
buffer.append(":")
|
|
||||||
buffer.append(path.toString())
|
|
||||||
if(read == true) {
|
|
||||||
buffer.setCharAt(0, 'r')
|
|
||||||
}
|
|
||||||
if(write == true) {
|
|
||||||
buffer.setCharAt(1, 'w')
|
|
||||||
}
|
|
||||||
if(execute == true) {
|
|
||||||
buffer.setCharAt(2, 'x')
|
|
||||||
}
|
|
||||||
return buffer.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the `xdg-dbus-proxy` process.
|
|
||||||
* @param see Set `see` policy for `NAME` (`--see=NAME`)
|
|
||||||
* @param talk Set `talk` policy for `NAME` (`--talk=NAME`)
|
|
||||||
* @param own Set `own` policy for `NAME` (`--own=NAME)
|
|
||||||
* @param call Set `RULE` for calls on `NAME` (`--call=NAME=RULE`)
|
|
||||||
* @param broadcast Set `RULE` for broadcasts from `NAME` (`--broadcast=NAME=RULE`)
|
|
||||||
* @param log Turn on logging (`--log`)
|
|
||||||
* @param filter Enable filtering (`--filter`)
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
data class DBusConfig(
|
|
||||||
var see: List<String>? = null,
|
|
||||||
var talk: List<String>? = null,
|
|
||||||
var own: List<String>? = null,
|
|
||||||
var call: Map<String, String>? = null,
|
|
||||||
var broadcast: Map<String, String>? = null,
|
|
||||||
var log: Boolean? = null,
|
|
||||||
var filter: Boolean? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an optional host service to export to the target user.
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
data class Enablements(
|
|
||||||
var wayland: Boolean? = null,
|
|
||||||
var x11: Boolean? = null,
|
|
||||||
var dbus: Boolean? = null,
|
|
||||||
var pulse: Boolean? = null,
|
|
||||||
)
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import moe.rosa.planterette.dsl.*
|
|
||||||
import moe.rosa.planterette.dsl.DSLEnablements.*
|
|
||||||
import kotlin.test.*
|
|
||||||
|
|
||||||
class HakureiDSLTest {
|
|
||||||
companion object {
|
|
||||||
val HAKUREI_DSL_TEST = planterette {
|
|
||||||
hakurei("org.chromium.Chromium") {
|
|
||||||
|
|
||||||
enable(Wayland, DBus, Pulse)
|
|
||||||
dbus {
|
|
||||||
session {
|
|
||||||
talk("org.freedesktop.Notifications",
|
|
||||||
"org.freedesktop.FileManager1",
|
|
||||||
"org.freedesktop.ScreenSaver",
|
|
||||||
"org.freedesktop.secrets",
|
|
||||||
"org.kde.kwalletd5",
|
|
||||||
"org.kde.kwalletd6",
|
|
||||||
"org.gnome.SessionManager")
|
|
||||||
own("org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.chromium.*")
|
|
||||||
call("org.freedesktop.portal.*" to "*")
|
|
||||||
broadcast("org.freedesktop.portal.*" to "@/org/freedesktop/portal/*")
|
|
||||||
filter()
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
talk("org.bluez",
|
|
||||||
"org.freedesktop.Avahi",
|
|
||||||
"org.freedesktop.UPower")
|
|
||||||
filter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extraPerms(
|
|
||||||
perm("/var/lib/hakurei/u0") {
|
|
||||||
ensure()
|
|
||||||
execute()
|
|
||||||
},
|
|
||||||
perm("/var/lib/hakurei/u0/org.chromium.Chromium", rwx = "rwx")
|
|
||||||
)
|
|
||||||
identity(9)
|
|
||||||
groups("video",
|
|
||||||
"dialout",
|
|
||||||
"plugdev")
|
|
||||||
container {
|
|
||||||
hostname("localhost")
|
|
||||||
noTimeout()
|
|
||||||
seccompCompat()
|
|
||||||
devel()
|
|
||||||
userns()
|
|
||||||
hostNet()
|
|
||||||
hostAbstract()
|
|
||||||
tty()
|
|
||||||
multiarch()
|
|
||||||
env("GOOGLE_API_KEY" to "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
|
||||||
"GOOGLE_DEFAULT_CLIENT_ID" to "77185425430.apps.googleusercontent.com",
|
|
||||||
"GOOGLE_DEFAULT_CLIENT_SECRET" to "OTJgUOQcT7lO7GsGZq2G4IlT")
|
|
||||||
mapRealUid()
|
|
||||||
device()
|
|
||||||
executable("/run/current-system/sw/bin/chromium",
|
|
||||||
"chromium",
|
|
||||||
"--ignore-gpu-blocklist",
|
|
||||||
"--disable-smooth-scrolling",
|
|
||||||
"--enable-features=UseOzonePlatform",
|
|
||||||
"--ozone-platform=wayland"
|
|
||||||
)
|
|
||||||
username("chronos")
|
|
||||||
shell("/run/current-system/sw/bin/zsh")
|
|
||||||
home("/data/data/org.chromium.Chromium")
|
|
||||||
filesystem {
|
|
||||||
bind("/var/lib/hakurei/base/org.debian" to "/") {
|
|
||||||
write()
|
|
||||||
special()
|
|
||||||
}
|
|
||||||
bind("/etc/" to "/etc/") {
|
|
||||||
special()
|
|
||||||
}
|
|
||||||
ephemeral("/tmp/") {
|
|
||||||
write()
|
|
||||||
perm(493)
|
|
||||||
}
|
|
||||||
overlay("/nix/store") {
|
|
||||||
lower("/var/lib/hakurei/base/org.nixos/ro-store")
|
|
||||||
upper("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper")
|
|
||||||
work("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work")
|
|
||||||
}
|
|
||||||
link("/run/current-system") {
|
|
||||||
dereference()
|
|
||||||
}
|
|
||||||
link("/run/opengl-driver") {
|
|
||||||
dereference()
|
|
||||||
}
|
|
||||||
bind("/var/lib/hakurei/u0/org.chromium.Chromium" to "/data/data/org.chromium.Chromium") {
|
|
||||||
write()
|
|
||||||
ensure()
|
|
||||||
}
|
|
||||||
bind("/dev/dri") {
|
|
||||||
device()
|
|
||||||
optional()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
fun hakureiDSLTest() {
|
|
||||||
assertEquals(HakureiTest.TEMPLATE_DATA, HAKUREI_DSL_TEST.hakurei)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import moe.rosa.planterette.hakurei.*
|
|
||||||
import org.junit.jupiter.api.assertDoesNotThrow
|
|
||||||
import kotlin.test.*
|
|
||||||
|
|
||||||
class HakureiTest {
|
|
||||||
companion object {
|
|
||||||
val TEMPLATE_DATA = HakureiConfig(
|
|
||||||
id = "org.chromium.Chromium",
|
|
||||||
|
|
||||||
enablements = Enablements(
|
|
||||||
wayland = true,
|
|
||||||
dbus = true,
|
|
||||||
pulse = true
|
|
||||||
),
|
|
||||||
sessionBus = DBusConfig(
|
|
||||||
see = null,
|
|
||||||
talk = listOf(
|
|
||||||
"org.freedesktop.Notifications",
|
|
||||||
"org.freedesktop.FileManager1",
|
|
||||||
"org.freedesktop.ScreenSaver",
|
|
||||||
"org.freedesktop.secrets",
|
|
||||||
"org.kde.kwalletd5",
|
|
||||||
"org.kde.kwalletd6",
|
|
||||||
"org.gnome.SessionManager"
|
|
||||||
),
|
|
||||||
own = listOf(
|
|
||||||
"org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.chromium.*"
|
|
||||||
),
|
|
||||||
call = mapOf(
|
|
||||||
"org.freedesktop.portal.*" to "*"
|
|
||||||
),
|
|
||||||
broadcast = mapOf(
|
|
||||||
"org.freedesktop.portal.*" to "@/org/freedesktop/portal/*"
|
|
||||||
),
|
|
||||||
filter = true
|
|
||||||
),
|
|
||||||
systemBus = DBusConfig(
|
|
||||||
see = null,
|
|
||||||
talk = listOf(
|
|
||||||
"org.bluez",
|
|
||||||
"org.freedesktop.Avahi",
|
|
||||||
"org.freedesktop.UPower"
|
|
||||||
),
|
|
||||||
own = null,
|
|
||||||
call = null,
|
|
||||||
broadcast = null,
|
|
||||||
filter = true
|
|
||||||
),
|
|
||||||
|
|
||||||
extraPerms = listOf(
|
|
||||||
ExtraPermsConfig(
|
|
||||||
ensure = true,
|
|
||||||
path = AbsolutePath("/var/lib/hakurei/u0"),
|
|
||||||
read = null,
|
|
||||||
write = null,
|
|
||||||
execute = true,
|
|
||||||
),
|
|
||||||
ExtraPermsConfig(
|
|
||||||
ensure = null,
|
|
||||||
path = AbsolutePath("/var/lib/hakurei/u0/org.chromium.Chromium"),
|
|
||||||
read = true,
|
|
||||||
write = true,
|
|
||||||
execute = true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
identity = 9,
|
|
||||||
groups = listOf(
|
|
||||||
"video",
|
|
||||||
"dialout",
|
|
||||||
"plugdev"
|
|
||||||
),
|
|
||||||
container = ContainerConfig(
|
|
||||||
hostname = "localhost",
|
|
||||||
waitDelay = -1,
|
|
||||||
seccompCompat = true,
|
|
||||||
devel = true,
|
|
||||||
userns = true,
|
|
||||||
hostNet = true,
|
|
||||||
hostAbstract = true,
|
|
||||||
tty = true,
|
|
||||||
multiarch = true,
|
|
||||||
env = mapOf(
|
|
||||||
"GOOGLE_API_KEY" to "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
|
||||||
"GOOGLE_DEFAULT_CLIENT_ID" to "77185425430.apps.googleusercontent.com",
|
|
||||||
"GOOGLE_DEFAULT_CLIENT_SECRET" to "OTJgUOQcT7lO7GsGZq2G4IlT"
|
|
||||||
),
|
|
||||||
mapRealUid = true,
|
|
||||||
device = true,
|
|
||||||
filesystem = listOf(
|
|
||||||
FSBind(
|
|
||||||
target = AbsolutePath("/"),
|
|
||||||
source = AbsolutePath("/var/lib/hakurei/base/org.debian"),
|
|
||||||
write = true,
|
|
||||||
special = true,
|
|
||||||
),
|
|
||||||
FSBind(
|
|
||||||
target = AbsolutePath("/etc/"),
|
|
||||||
source = AbsolutePath("/etc/"),
|
|
||||||
special = true,
|
|
||||||
),
|
|
||||||
FSEphemeral(
|
|
||||||
target = AbsolutePath("/tmp/"),
|
|
||||||
write = true,
|
|
||||||
perm = 493
|
|
||||||
),
|
|
||||||
FSOverlay(
|
|
||||||
target = AbsolutePath("/nix/store"),
|
|
||||||
lower = listOf(
|
|
||||||
AbsolutePath("/var/lib/hakurei/base/org.nixos/ro-store")
|
|
||||||
),
|
|
||||||
upper = AbsolutePath("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
|
||||||
work = AbsolutePath("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work")
|
|
||||||
),
|
|
||||||
FSLink(
|
|
||||||
target = AbsolutePath("/run/current-system"),
|
|
||||||
linkname = "/run/current-system",
|
|
||||||
dereference = true
|
|
||||||
),
|
|
||||||
FSLink(
|
|
||||||
target = AbsolutePath("/run/opengl-driver"),
|
|
||||||
linkname = "/run/opengl-driver",
|
|
||||||
dereference = true
|
|
||||||
),
|
|
||||||
FSBind(
|
|
||||||
target = AbsolutePath("/data/data/org.chromium.Chromium"),
|
|
||||||
source = AbsolutePath("/var/lib/hakurei/u0/org.chromium.Chromium"),
|
|
||||||
write = true,
|
|
||||||
ensure = true,
|
|
||||||
),
|
|
||||||
FSBind(
|
|
||||||
source = AbsolutePath("/dev/dri"),
|
|
||||||
device = true,
|
|
||||||
optional = true
|
|
||||||
)
|
|
||||||
),
|
|
||||||
|
|
||||||
username = "chronos",
|
|
||||||
shell = AbsolutePath("/run/current-system/sw/bin/zsh"),
|
|
||||||
home = AbsolutePath("/data/data/org.chromium.Chromium"),
|
|
||||||
path = AbsolutePath("/run/current-system/sw/bin/chromium"),
|
|
||||||
args = listOf(
|
|
||||||
"chromium",
|
|
||||||
"--ignore-gpu-blocklist",
|
|
||||||
"--disable-smooth-scrolling",
|
|
||||||
"--enable-features=UseOzonePlatform",
|
|
||||||
"--ozone-platform=wayland"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val TEMPLATE_JSON = ProcessBuilder("hakurei", "template")
|
|
||||||
.start()
|
|
||||||
.inputStream
|
|
||||||
.readAllBytes()
|
|
||||||
.toString(Charsets.UTF_8)
|
|
||||||
val format = Json {
|
|
||||||
prettyPrint = true
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
@Test
|
|
||||||
fun deserializeTest() {
|
|
||||||
|
|
||||||
println(TEMPLATE_JSON)
|
|
||||||
val want = format.decodeFromString<HakureiConfig>(TEMPLATE_JSON)
|
|
||||||
assertEquals(TEMPLATE_DATA, want)
|
|
||||||
}
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
@Test
|
|
||||||
fun serializeTest() {
|
|
||||||
val encoded = format.encodeToString(TEMPLATE_DATA)
|
|
||||||
val decoded = format.decodeFromString<HakureiConfig>(encoded)
|
|
||||||
assertEquals(TEMPLATE_DATA, decoded)
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
fun absolutePathTest() {
|
|
||||||
assertDoesNotThrow {
|
|
||||||
AbsolutePath("/test/absolutepath")
|
|
||||||
}
|
|
||||||
assertFailsWith(AbsolutePathException::class) {
|
|
||||||
AbsolutePath("./../../../../")
|
|
||||||
}
|
|
||||||
assertEquals(AbsolutePath("/test/absolutepath"), AbsolutePath("/test/") + "absolutepath")
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
fun extraPermsTest() {
|
|
||||||
assertIs<String>(TEMPLATE_DATA.extraPerms.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user