diff --git a/.gitignore b/.gitignore
index b1dff0d..9a4bdaa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1,11 @@
-.gradle
-build/
-!gradle/wrapper/gradle-wrapper.jar
+### Gradle/Java ###
+**/.gradle
+**/build/
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
-.idea/modules.xml
-.idea/jarRepositories.xml
-.idea/compiler.xml
-.idea/libraries/
+**/.idea
*.iws
*.iml
*.ipr
@@ -42,4 +39,10 @@ bin/
.vscode/
### Mac OS ###
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+### Go ###
+go.sum
+
+### Build ###
+/hakureiUpdate.sh
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 26d3352..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 1bec35e..0000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index 79ee123..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 295bdcf..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
deleted file mode 100644
index 3efb2d8..0000000
--- a/.idea/kotlinc.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index b861657..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
deleted file mode 100644
index f005f4a..0000000
--- a/build.gradle.kts
+++ /dev/null
@@ -1,19 +0,0 @@
-tasks.register("build").configure {
- group = "build"
- dependsOn("test")
- dependsOn(":plt-build:build")
- dependsOn(":plt-build-wrapper:compileGo")
- dependsOn(":plt-fetch:compileGo")
- dependsOn(":plt-pkg:compileGo")
- dependsOn(":plt-server:compileGo")
- dependsOn(":plt-updated:compileGo")
-}
-tasks.register("test").configure {
- group = "verification"
- dependsOn(":plt-build:test")
- dependsOn(":plt-build-wrapper:testGo")
- dependsOn(":plt-fetch:testGo")
- dependsOn(":plt-pkg:testGo")
- dependsOn(":plt-server:testGo")
- dependsOn(":plt-updated:testGo")
-}
\ No newline at end of file
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
deleted file mode 100644
index 33aba19..0000000
--- a/buildSrc/build.gradle.kts
+++ /dev/null
@@ -1,15 +0,0 @@
-plugins {
- `kotlin-dsl`
-}
-repositories {
- gradlePluginPortal()
-}
-
-gradlePlugin {
- plugins {
- create("goPlugin") {
- id = "goPlugin"
- implementationClass = "moe.rosa.planterette.buildsrc.GoPlugin"
- }
- }
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/moe/rosa/planterette/buildsrc/GoPlugin.kt b/buildSrc/src/main/kotlin/moe/rosa/planterette/buildsrc/GoPlugin.kt
deleted file mode 100644
index c3c2bde..0000000
--- a/buildSrc/src/main/kotlin/moe/rosa/planterette/buildsrc/GoPlugin.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package moe.rosa.planterette.buildsrc
-
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.tasks.Exec
-
-@Suppress("unused") // FIXME(mae) i have literally no clue why idea thinks GoPlugin is unused
-class GoPlugin : Plugin {
- override fun apply(project: Project) {
- project.tasks.register("compileGo", Exec::class.java) {
- group = "go"
- description = "compile all go source files and output into build directory"
- workingDir(project.layout.projectDirectory)
- commandLine("go", "build", "-o", "../build/go/${project.name}")
- }
- project.tasks.register("runGo", Exec::class.java) {
- group = "go"
- description = "run go application"
- workingDir(project.layout.projectDirectory)
- commandLine("go", "run", "main.go")
- }
- project.tasks.register("testGo", Exec::class.java) {
- group = "go"
- description = "run go test"
- workingDir(project.layout.projectDirectory)
- commandLine("go", "test")
- }
- }
-}
\ No newline at end of file
diff --git a/plt-build-wrapper/main.go b/cmd/plt-build-wrapper/main.go
similarity index 100%
rename from plt-build-wrapper/main.go
rename to cmd/plt-build-wrapper/main.go
diff --git a/cmd/plt-build-wrapper/main_test.go b/cmd/plt-build-wrapper/main_test.go
new file mode 100644
index 0000000..06c0efd
--- /dev/null
+++ b/cmd/plt-build-wrapper/main_test.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "testing"
+)
+
+func TestPltBuildWrapper(t *testing.T) {
+
+}
diff --git a/plt-build/build.gradle.kts b/cmd/plt-build/build.gradle.kts
similarity index 100%
rename from plt-build/build.gradle.kts
rename to cmd/plt-build/build.gradle.kts
diff --git a/gradle.properties b/cmd/plt-build/gradle.properties
similarity index 100%
rename from gradle.properties
rename to cmd/plt-build/gradle.properties
diff --git a/gradle/wrapper/gradle-wrapper.jar b/cmd/plt-build/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from gradle/wrapper/gradle-wrapper.jar
rename to cmd/plt-build/gradle/wrapper/gradle-wrapper.jar
diff --git a/gradle/wrapper/gradle-wrapper.properties b/cmd/plt-build/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from gradle/wrapper/gradle-wrapper.properties
rename to cmd/plt-build/gradle/wrapper/gradle-wrapper.properties
diff --git a/gradlew b/cmd/plt-build/gradlew
similarity index 100%
rename from gradlew
rename to cmd/plt-build/gradlew
diff --git a/cmd/plt-build/main.go b/cmd/plt-build/main.go
new file mode 100644
index 0000000..c6f661d
--- /dev/null
+++ b/cmd/plt-build/main.go
@@ -0,0 +1,2 @@
+//go:generate ./gradlew build
+package plt_build
diff --git a/cmd/plt-build/main_test.go b/cmd/plt-build/main_test.go
new file mode 100644
index 0000000..a8ce81e
--- /dev/null
+++ b/cmd/plt-build/main_test.go
@@ -0,0 +1,19 @@
+package plt_build
+
+import (
+ "os"
+ "os/exec"
+ "testing"
+ "time"
+)
+
+func TestPltBuild(t *testing.T) {
+ cmd := exec.CommandContext(t.Context(), "./gradlew", "test")
+ cmd.WaitDelay = 100 * time.Millisecond
+ cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
+ err := cmd.Run()
+
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/plt-build/settings.gradle.kts b/cmd/plt-build/settings.gradle.kts
similarity index 100%
rename from plt-build/settings.gradle.kts
rename to cmd/plt-build/settings.gradle.kts
diff --git a/plt-build/src/main/kotlin/moe/rosa/planterette/PlanteretteConfig.kt b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/PlanteretteConfig.kt
similarity index 51%
rename from plt-build/src/main/kotlin/moe/rosa/planterette/PlanteretteConfig.kt
rename to cmd/plt-build/src/main/kotlin/moe/rosa/planterette/PlanteretteConfig.kt
index 709c92b..7f8ebb6 100644
--- a/plt-build/src/main/kotlin/moe/rosa/planterette/PlanteretteConfig.kt
+++ b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/PlanteretteConfig.kt
@@ -2,4 +2,8 @@ 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?)
\ No newline at end of file
diff --git a/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/DSL.kt b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/DSL.kt
similarity index 100%
rename from plt-build/src/main/kotlin/moe/rosa/planterette/dsl/DSL.kt
rename to cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/DSL.kt
diff --git a/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/HakureiDSL.kt b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/HakureiDSL.kt
similarity index 97%
rename from plt-build/src/main/kotlin/moe/rosa/planterette/dsl/HakureiDSL.kt
rename to cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/HakureiDSL.kt
index 01f50ff..af7d2cc 100644
--- a/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/HakureiDSL.kt
+++ b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/HakureiDSL.kt
@@ -44,11 +44,7 @@ annotation class FSOverlayDSL
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,
@@ -73,18 +69,7 @@ fun HakureiConfig.enable(vararg enablements: DSLEnablements) {
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) {
@@ -237,7 +222,23 @@ fun ContainerConfig.mapRealUid(mapRealUid: Boolean = true) {
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 = mutableListOf())
diff --git a/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/MetadataDSL.kt b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/MetadataDSL.kt
new file mode 100644
index 0000000..c2329c7
--- /dev/null
+++ b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/dsl/MetadataDSL.kt
@@ -0,0 +1,8 @@
+package moe.rosa.planterette.dsl
+
+import moe.rosa.planterette.PlanteretteConfig
+
+@PlanteretteDSL
+fun PlanteretteConfig.metadata() {
+
+}
\ No newline at end of file
diff --git a/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Filesystem.kt b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Filesystem.kt
new file mode 100644
index 0000000..5a486e8
--- /dev/null
+++ b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Filesystem.kt
@@ -0,0 +1,181 @@
+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 {
+ 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,
+ val upper: AbsolutePath? = null,
+ val work: AbsolutePath? = null,
+) : FilesystemConfig
\ No newline at end of file
diff --git a/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Hakurei.kt b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Hakurei.kt
new file mode 100644
index 0000000..f46a574
--- /dev/null
+++ b/cmd/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Hakurei.kt
@@ -0,0 +1,162 @@
+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? = null,
+ var identity: Int? = null,
+ var groups: List? = 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? = null,
+
+ @SerialName("map_real_uid") var mapRealUid: Boolean? = null,
+ var device: Boolean? = null,
+
+ var filesystem: List? = null,
+
+ var username: String? = "chronos",
+ var shell: AbsolutePath? = null,
+ var home: AbsolutePath? = null,
+ var path: AbsolutePath? = null,
+ var args: List? = 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? = null,
+ var talk: List? = null,
+ var own: List? = null,
+ var call: Map? = null,
+ var broadcast: Map? = 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,
+)
diff --git a/plt-build/src/test/kotlin/DSLTest.kt b/cmd/plt-build/src/test/kotlin/HakureiDSLTest.kt
similarity index 87%
rename from plt-build/src/test/kotlin/DSLTest.kt
rename to cmd/plt-build/src/test/kotlin/HakureiDSLTest.kt
index 0044dab..7d4a5f2 100644
--- a/plt-build/src/test/kotlin/DSLTest.kt
+++ b/cmd/plt-build/src/test/kotlin/HakureiDSLTest.kt
@@ -1,19 +1,12 @@
import moe.rosa.planterette.dsl.*
import moe.rosa.planterette.dsl.DSLEnablements.*
-import kotlin.test.Test
-import kotlin.test.assertEquals
+import kotlin.test.*
-class DSLTest {
+class HakureiDSLTest {
companion object {
val HAKUREI_DSL_TEST = planterette {
hakurei("org.chromium.Chromium") {
- executable("/run/current-system/sw/bin/chromium",
- "chromium",
- "--ignore-gpu-blocklist",
- "--disable-smooth-scrolling",
- "--enable-features=UseOzonePlatform",
- "--ozone-platform=wayland"
- )
+
enable(Wayland, DBus, Pulse)
dbus {
session {
@@ -38,9 +31,7 @@ class DSLTest {
filter()
}
}
- username("chronos")
- shell("/run/current-system/sw/bin/zsh")
- home("/data/data/org.chromium.Chromium")
+
extraPerms(
perm("/var/lib/hakurei/u0") {
ensure()
@@ -67,6 +58,16 @@ class DSLTest {
"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()
@@ -80,11 +81,10 @@ class DSLTest {
perm(493)
}
overlay("/nix/store") {
- lower("/mnt-root/nix/.ro-store")
- upper("/mnt-root/nix/.rw-store/upper")
- work("/mnt-root/nix/.rw-store/work")
+ 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")
}
- bind("/nix/store")
link("/run/current-system") {
dereference()
}
diff --git a/plt-build/src/test/kotlin/HakureiTest.kt b/cmd/plt-build/src/test/kotlin/HakureiTest.kt
similarity index 87%
rename from plt-build/src/test/kotlin/HakureiTest.kt
rename to cmd/plt-build/src/test/kotlin/HakureiTest.kt
index ad5537f..e3347d0 100644
--- a/plt-build/src/test/kotlin/HakureiTest.kt
+++ b/cmd/plt-build/src/test/kotlin/HakureiTest.kt
@@ -8,14 +8,7 @@ class HakureiTest {
companion object {
val TEMPLATE_DATA = HakureiConfig(
id = "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"
- ),
+
enablements = Enablements(
wayland = true,
dbus = true,
@@ -57,9 +50,7 @@ class HakureiTest {
broadcast = null,
filter = true
),
- username = "chronos",
- shell = AbsolutePath("/run/current-system/sw/bin/zsh"),
- home = AbsolutePath("/data/data/org.chromium.Chromium"),
+
extraPerms = listOf(
ExtraPermsConfig(
ensure = true,
@@ -119,13 +110,10 @@ class HakureiTest {
FSOverlay(
target = AbsolutePath("/nix/store"),
lower = listOf(
- AbsolutePath("/mnt-root/nix/.ro-store")
+ AbsolutePath("/var/lib/hakurei/base/org.nixos/ro-store")
),
- upper = AbsolutePath("/mnt-root/nix/.rw-store/upper"),
- work = AbsolutePath("/mnt-root/nix/.rw-store/work")
- ),
- FSBind(
- source = AbsolutePath("/nix/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"),
@@ -148,7 +136,19 @@ class HakureiTest {
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")
diff --git a/plt-fetch/main.go b/cmd/plt-fetch/main.go
similarity index 100%
rename from plt-fetch/main.go
rename to cmd/plt-fetch/main.go
diff --git a/plt-build-wrapper/main_test.go b/cmd/plt-fetch/main_test.go
similarity index 52%
rename from plt-build-wrapper/main_test.go
rename to cmd/plt-fetch/main_test.go
index 76b32fb..8967edc 100644
--- a/plt-build-wrapper/main_test.go
+++ b/cmd/plt-fetch/main_test.go
@@ -4,6 +4,6 @@ import (
"testing"
)
-func TestHelloWorld(t *testing.T) {
+func TestPltFetch(t *testing.T) {
}
diff --git a/plt-pkg/main.go b/cmd/plt-pkg/main.go
similarity index 100%
rename from plt-pkg/main.go
rename to cmd/plt-pkg/main.go
diff --git a/plt-server/main_test.go b/cmd/plt-pkg/main_test.go
similarity index 52%
rename from plt-server/main_test.go
rename to cmd/plt-pkg/main_test.go
index 76b32fb..acc383a 100644
--- a/plt-server/main_test.go
+++ b/cmd/plt-pkg/main_test.go
@@ -4,6 +4,6 @@ import (
"testing"
)
-func TestHelloWorld(t *testing.T) {
+func TestPltPkg(t *testing.T) {
}
diff --git a/plt-server/main.go b/cmd/plt-server/main.go
similarity index 100%
rename from plt-server/main.go
rename to cmd/plt-server/main.go
diff --git a/plt-fetch/main_test.go b/cmd/plt-server/main_test.go
similarity index 52%
rename from plt-fetch/main_test.go
rename to cmd/plt-server/main_test.go
index 76b32fb..2162747 100644
--- a/plt-fetch/main_test.go
+++ b/cmd/plt-server/main_test.go
@@ -4,6 +4,6 @@ import (
"testing"
)
-func TestHelloWorld(t *testing.T) {
+func TestPltServer(t *testing.T) {
}
diff --git a/plt-updated/main.go b/cmd/plt-updated/main.go
similarity index 100%
rename from plt-updated/main.go
rename to cmd/plt-updated/main.go
diff --git a/plt-pkg/main_test.go b/cmd/plt-updated/main_test.go
similarity index 52%
rename from plt-pkg/main_test.go
rename to cmd/plt-updated/main_test.go
index 76b32fb..be7ebc2 100644
--- a/plt-pkg/main_test.go
+++ b/cmd/plt-updated/main_test.go
@@ -4,6 +4,6 @@ import (
"testing"
)
-func TestHelloWorld(t *testing.T) {
+func TestPltUpdated(t *testing.T) {
}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..6f68a5f
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module rosa.moe/planterette
+
+go 1.24.9
+
+require hakurei.app v0.3.1 // indirect
diff --git a/gradlew.bat b/gradlew.bat
deleted file mode 100644
index ac1b06f..0000000
--- a/gradlew.bat
+++ /dev/null
@@ -1,89 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/plt-build-wrapper/build.gradle.kts b/plt-build-wrapper/build.gradle.kts
deleted file mode 100644
index f942929..0000000
--- a/plt-build-wrapper/build.gradle.kts
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins {
- id("goPlugin")
-}
\ No newline at end of file
diff --git a/plt-build-wrapper/go.mod b/plt-build-wrapper/go.mod
deleted file mode 100644
index 598c3f6..0000000
--- a/plt-build-wrapper/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module plt-build-wrapper
-
-go 1.24
diff --git a/plt-build/src/main/kotlin/moe/rosa/planterette/Main.kt b/plt-build/src/main/kotlin/moe/rosa/planterette/Main.kt
deleted file mode 100644
index aba9c1a..0000000
--- a/plt-build/src/main/kotlin/moe/rosa/planterette/Main.kt
+++ /dev/null
@@ -1,2 +0,0 @@
-package moe.rosa.planterette
-
diff --git a/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Filesystem.kt b/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Filesystem.kt
deleted file mode 100644
index 1aaa5c3..0000000
--- a/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Filesystem.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package moe.rosa.planterette.hakurei
-
-import kotlinx.serialization.*
-import kotlinx.serialization.descriptors.*
-import kotlinx.serialization.encoding.*
-
-import java.nio.file.Path
-
-/**
- * AbsolutePath 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)
- }
- }
- operator fun plus(other: String): AbsolutePath {
- return AbsolutePath(pathname + other)
- }
- companion object {
- fun isAbsolute(pathname: String): Boolean {
- return Path.of(pathname).isAbsolute
- }
- }
-}
-
-object AbsolutePathSerializer : KSerializer {
- 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)
- }
-}
-
-/**
- * AbsolutePathException is returned by @see AbsolutePath() and holds the invalid pathname.
- */
-data class AbsolutePathException(val pathname: String) : IllegalArgumentException("Path $pathname is not absolute")
-
-@Serializable sealed interface FilesystemConfig
-
-@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
-
-@Serializable
-@SerialName("ephemeral")
-data class FSEphemeral(
- @SerialName("dst") val target: AbsolutePath,
- val write: Boolean,
- val size: Int? = null,
- val perm: Int,
-) : FilesystemConfig
-
-@Serializable
-@SerialName("link")
-data class FSLink(
- @SerialName("dst") val target: AbsolutePath,
- val linkname: String,
- val dereference: Boolean,
-) : FilesystemConfig
-
-@Serializable
-@SerialName("overlay")
-data class FSOverlay(
- @SerialName("dst") val target: AbsolutePath,
- val lower: List,
- val upper: AbsolutePath,
- val work: AbsolutePath,
-) : FilesystemConfig
\ No newline at end of file
diff --git a/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Hakurei.kt b/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Hakurei.kt
deleted file mode 100644
index b3528d1..0000000
--- a/plt-build/src/main/kotlin/moe/rosa/planterette/hakurei/Hakurei.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package moe.rosa.planterette.hakurei
-
-import kotlinx.serialization.*
-
-@Serializable
-data class HakureiConfig(
- var id: String? = null,
- var path: AbsolutePath? = null,
- var args: List? = 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,
- var username: String? = null,
- var shell: AbsolutePath? = null,
- var home: AbsolutePath? = null,
-
- @SerialName("extra_perms") var extraPerms: List? = null,
- var identity: Int? = null,
- var groups: List? = null,
-
- var container: ContainerConfig? = null,
-)
-
-@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? = null,
-
- @SerialName("map_real_uid") var mapRealUid: Boolean? = null,
- var device: Boolean? = null,
-
- var filesystem: List? = null,
-)
-
-@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()
- }
-}
-
-@Serializable
-data class DBusConfig(
- var see: List? = null,
- var talk: List? = null,
- var own: List? = null,
- var call: Map? = null,
- var broadcast: Map? = null,
- var log: Boolean? = null,
- var filter: Boolean? = null,
-)
-
-@Serializable
-data class Enablements(
- var wayland: Boolean? = null,
- var x11: Boolean? = null,
- var dbus: Boolean? = null,
- var pulse: Boolean? = null,
-)
diff --git a/plt-build/src/test/resources/ChromiumExample.kts b/plt-build/src/test/resources/ChromiumExample.kts
deleted file mode 100644
index e69de29..0000000
diff --git a/plt-fetch/build.gradle.kts b/plt-fetch/build.gradle.kts
deleted file mode 100644
index f942929..0000000
--- a/plt-fetch/build.gradle.kts
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins {
- id("goPlugin")
-}
\ No newline at end of file
diff --git a/plt-fetch/go.mod b/plt-fetch/go.mod
deleted file mode 100644
index cce4de5..0000000
--- a/plt-fetch/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module plt-fetch
-
-go 1.24
diff --git a/plt-pkg/build.gradle.kts b/plt-pkg/build.gradle.kts
deleted file mode 100644
index f942929..0000000
--- a/plt-pkg/build.gradle.kts
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins {
- id("goPlugin")
-}
\ No newline at end of file
diff --git a/plt-pkg/go.mod b/plt-pkg/go.mod
deleted file mode 100644
index 1845e72..0000000
--- a/plt-pkg/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module plt-pkg
-
-go 1.24
diff --git a/plt-server/build.gradle.kts b/plt-server/build.gradle.kts
deleted file mode 100644
index f942929..0000000
--- a/plt-server/build.gradle.kts
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins {
- id("goPlugin")
-}
\ No newline at end of file
diff --git a/plt-server/go.mod b/plt-server/go.mod
deleted file mode 100644
index 71d8b4e..0000000
--- a/plt-server/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module plt-server
-
-go 1.24
diff --git a/plt-updated/build.gradle.kts b/plt-updated/build.gradle.kts
deleted file mode 100644
index f942929..0000000
--- a/plt-updated/build.gradle.kts
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins {
- id("goPlugin")
-}
\ No newline at end of file
diff --git a/plt-updated/go.mod b/plt-updated/go.mod
deleted file mode 100644
index 4d28f79..0000000
--- a/plt-updated/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module plt-updated
-
-go 1.24
diff --git a/plt-updated/main_test.go b/plt-updated/main_test.go
deleted file mode 100644
index 76b32fb..0000000
--- a/plt-updated/main_test.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package main
-
-import (
- "testing"
-)
-
-func TestHelloWorld(t *testing.T) {
-
-}
diff --git a/settings.gradle.kts b/settings.gradle.kts
deleted file mode 100644
index 4878082..0000000
--- a/settings.gradle.kts
+++ /dev/null
@@ -1,6 +0,0 @@
-include("plt-build")
-include("plt-build-wrapper")
-include("plt-fetch")
-include("plt-pkg")
-include("plt-server")
-include("plt-updated")