create PackageManifest.kt and get test working

This commit is contained in:
lilly 2025-07-30 03:15:37 -05:00
parent 0baf6b876b
commit c14a7be42a
Signed by: maemachinebroke
GPG Key ID: B54591A4805E9CC8
21 changed files with 361 additions and 70 deletions

4
.gitignore vendored
View File

@ -42,4 +42,6 @@ bin/
.vscode/
### Mac OS ###
.DS_Store
.DS_Store
/app/src/test/resources/debian-images/
/app/src/test/resources/squashfs-root/

8
.idea/artifacts/api_jvm.xml generated Normal file
View File

@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="api-jvm">
<output-path>$PROJECT_DIR$/api/build/libs</output-path>
<root id="archive" name="api-jvm.jar">
<element id="module-output" name="planterette.api.jvmMain" />
</root>
</artifact>
</component>

8
.idea/dictionaries/project.xml generated Normal file
View File

@ -0,0 +1,8 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>buildsrc</w>
<w>planterette</w>
</words>
</dictionary>
</component>

22
.idea/gradle.xml generated
View File

@ -1,10 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<compositeConfiguration>
<compositeBuild compositeDefinitionSource="SCRIPT">
<builds>
<build path="$PROJECT_DIR$/buildSrc" name="buildSrc">
<projects>
<project path="$PROJECT_DIR$/buildSrc" />
</projects>
</build>
</builds>
</compositeBuild>
</compositeConfiguration>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/api" />
<option value="$PROJECT_DIR$/buildSrc" />
<option value="$PROJECT_DIR$/cli" />
<option value="$PROJECT_DIR$/daemon" />
<option value="$PROJECT_DIR$/gui" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>

12
.idea/kotlinc.xml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Kotlin2JsCompilerArguments">
<option name="moduleKind" value="plain" />
</component>
<component name="Kotlin2JvmCompilerArguments">
<option name="jvmTarget" value="1.8" />
</component>
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.2.0" />
</component>
</project>

View File

@ -1,9 +1,32 @@
plugins {
id("buildsrc.convention.kotlin-jvm")
kotlin("multiplatform")
alias(libs.plugins.kotlinPluginSerialization)
}
kotlin {
jvm()
val nativeTarget = if(System.getProperty("os.arch") == "aarch64") {
linuxArm64("native")
} else {
linuxX64("native")
}
nativeTarget.binaries {
sharedLib {
baseName = "planterette"
}
}
sourceSets {
commonMain.dependencies {
implementation(libs.bundles.kotlinxEcosystem)
}
commonTest.dependencies {
implementation(libs.bundles.kotlinxEcosystem)
implementation(kotlin("test"))
}
jvmMain.dependencies {
dependencies {
implementation(libs.bundles.kotlinxEcosystem)
testImplementation(kotlin("test"))
}
}
jvmTest.dependencies {
}
}
}

View File

@ -8,35 +8,37 @@ data class HakureiConfig(
val id: String,
val path: String? = null,
val args: Array<String>,
val args: List<String>,
val enablements: Byte,
@SerialName("session_bus") val sessionBus: DbusConfig?,
@SerialName("system_bus") val systemBus: DbusConfig?,
@SerialName("direct_wayland") val directWayland: Boolean?,
@SerialName("session_bus") val sessionBus: DbusConfig? = null,
@SerialName("system_bus") val systemBus: DbusConfig? = null,
@SerialName("direct_wayland") val directWayland: Boolean? = null,
val username: String? = null,
val shell: String? = null,
val data: String,
val dir: String,
@SerialName("extra_perms") val extraPerms: Array<ExtraPermConfig>?,
@SerialName("extra_perms") val extraPerms: List<ExtraPermConfig>?,
val identity: Int,
val groups: Array<String>,
val groups: List<String>,
val container: ContainerConfig
) {
@Serializable
data class DbusConfig(
val see: Array<String>? = null,
val talk: Array<String>,
val own: Array<String>?,
val call: Map<String, String>?,
val broadcast: Map<String, String>?,
val log: Boolean,
val filter: Boolean
)
val see: List<String>? = null,
val talk: List<String>? = null,
val own: List<String>? = null,
val call: Map<String, String>? = null,
val broadcast: Map<String, String>? = null,
val log: Boolean? = null,
val filter: Boolean? = null
) {
}
@Serializable
data class ExtraPermConfig(
val ensure: Boolean? = null,
@ -48,7 +50,7 @@ data class HakureiConfig(
@Serializable
data class ContainerConfig(
val hostname: String? = null,
@SerialName("wait_delay") val delay: Int = -1,
@SerialName("seccomp_flags") val seccompFlags: Int,
@SerialName("seccomp_presets") val seccompPresets: Int,
@SerialName("seccomp_compat") val seccompCompat: Boolean? = null,
@ -63,29 +65,29 @@ data class HakureiConfig(
@SerialName("map_real_uid") val mapRealUid: Boolean,
val device: Boolean? = null,
val filesystem: Array<FilesystemConfig>,
@SerialName("symlink") val link: Array<String>,
val filesystem: List<FilesystemConfig>,
@SerialName("symlink") val link: List<String>,
val etc: String? = null,
@SerialName("auto_etc") val autoEtc: Boolean,
val cover: Array<String>
val cover: List<String>
)
@Serializable
data class FilesystemConfig(
val dst: String? = null,
val src: String,
val write: Boolean? = null,
val device: Boolean? = null,
@SerialName("dev") val device: Boolean? = null,
@SerialName("require") val must: Boolean? = null
)
@Serializable
enum class Enablement(val value: Int) {
Wayland(1 shl 0),
X11(1 shl 1),
DBus(1 shl 2),
Pulse(1 shl 3),
EM(0b10000);
Pulse(1 shl 3);
companion object {
fun enablements(vararg enablements: Enablement): Byte {
@ -93,6 +95,7 @@ data class HakureiConfig(
}
}
}
@Serializable
enum class SeccompFilterPreset(val value: Int) {
Ext(1 shl 0),
@ -107,6 +110,7 @@ data class HakureiConfig(
}
}
}
@Serializable
enum class HakureiExportFlag(val value: Int) {
Multiarch(1 shl 0),

View File

@ -0,0 +1,33 @@
package app.hakurei.planterette.api
import kotlinx.serialization.Serializable
@Serializable
data class PackageManifest(
val hakureiConfig: HakureiConfig,
val id: String,
val version: Version,
val name: String,
val description: String,
val architecture: List<Architecture>,
val baseImage: BaseImage
) {
@Serializable
data class Version(val version: String, val canonicalVersion: UInt)
@Serializable
enum class Architecture {
X86_64,
ARM64,
}
@Serializable
enum class BaseImage {
DEBIAN,
CHIMERA,
}
companion object {
val fileList = listOf("planterette.json", "icon.png", "image.tar")
val signatureFile = "package.sig"
}
}

View File

@ -0,0 +1,16 @@
package app.hakurei.planterette.api
import kotlinx.io.Buffer
import kotlinx.io.buffered
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
import kotlinx.io.readString
object Util {
fun readFileToString(path: String): String {
val buffer = Buffer()
val source = SystemFileSystem.source(Path(path))
source.buffered().transferTo(buffer)
return buffer.readString()
}
}

View File

@ -3,23 +3,22 @@ package app.hakurei.planterette.api
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import org.junit.jupiter.api.Test
import java.io.FileInputStream
import kotlin.test.asserter
import kotlin.test.Test
import kotlin.test.assertEquals
class HakureiConfigTest {
@OptIn(ExperimentalSerializationApi::class)
val format = Json {
explicitNulls = false
prettyPrint = true
}
val templateFile: String = javaClass.classLoader.getResource("template.json")!!.readText()
@Test
fun testHakureiConfigSerialization() {
val testConfig: HakureiConfig = HakureiConfig(
val testConfig = HakureiConfig(
id = "org.chromium.Chromium",
path = "/run/current-system/sw/bin/chromium",
args = arrayOf(
args = listOf(
"chromium",
"--ignore-gpu-blocklist",
"--disable-smooth-scrolling",
@ -30,36 +29,29 @@ class HakureiConfigTest {
HakureiConfig.Enablement.Pulse),
sessionBus = HakureiConfig.DbusConfig(
see = null,
talk = arrayOf("org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
talk = listOf("org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
"org.freedesktop.secrets", "org.kde.kwalletd5", "org.kde.kwalletd6", "org.gnome.SessionManager"),
own = arrayOf("org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
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/*"),
log = false,
filter = true
),
systemBus = HakureiConfig.DbusConfig(
see = null,
talk = arrayOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"),
own = null,
call = null,
broadcast = null,
log = false,
talk = listOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"),
filter = true
),
directWayland = false,
username = "chronos",
shell = "/run/current-system/sw/bin/zsh",
data = "/var/lib/hakurei/u0/org.chromium.Chromium",
dir = "/data/data/org.chromium.Chromium",
extraPerms = arrayOf(
extraPerms = listOf(
HakureiConfig.ExtraPermConfig(path = "/var/lib/hakurei/u0", ensure = true, execute = true),
HakureiConfig.ExtraPermConfig(path = "/var/lib/hakurei/u0/org.chromium.Chromium", read = true, write = true, execute = true)
),
identity = 9,
groups = arrayOf("video", "dialout", "plugdev"),
groups = listOf("video", "dialout", "plugdev"),
container = HakureiConfig.ContainerConfig(
hostname = "localhost",
devel = true,
@ -76,22 +68,30 @@ class HakureiConfigTest {
"GOOGLE_DEFAULT_CLIENT_ID" to "77185425430.apps.googleusercontent.com",
"GOOGLE_DEFAULT_CLIENT_SECRET" to "OTJgUOQcT7lO7GsGZq2G4IlT",
),
filesystem = arrayOf(
filesystem = listOf(
HakureiConfig.FilesystemConfig(src = "/nix/store"),
HakureiConfig.FilesystemConfig(src = "/run/current-system"),
HakureiConfig.FilesystemConfig(src = "/run/opengl-driver"),
HakureiConfig.FilesystemConfig(src = "/var/db/nix-channels"),
HakureiConfig.FilesystemConfig(src = "/var/lib/hakurei/u0/org.chromium.Chromium", dst = "/data/data/org.chromium.Chromium", write = true, must = true),
HakureiConfig.FilesystemConfig(
src = "/var/lib/hakurei/u0/org.chromium.Chromium",
dst = "/data/data/org.chromium.Chromium",
write = true,
must = true
),
HakureiConfig.FilesystemConfig(src = "/dev/dri", device = true)
),
link = arrayOf("/run/user/65534", "/run/user/150"),
link = listOf("/run/user/65534", "/run/user/150"),
etc = "/etc",
autoEtc = true,
cover = arrayOf("/var/run/nscd")
cover = listOf("/var/run/nscd"),
delay = -1,
seccompCompat = true
)
)
val json = format.encodeToString(serializer(), testConfig)
println("can't compare to template generated by go right now, so printing here. add \"prettyPrint = true\" to format to add whitespace")
println(json)
val deserializeJson: HakureiConfig = format.decodeFromString(json)
val templateJson: HakureiConfig = format.decodeFromString(Util.readFileToString("/home/lilly/Documents/Projects/Rosa/planterette/api/src/commonTest/resources/template.json"))
assertEquals(templateJson, deserializeJson, "")
}
}

View File

@ -70,8 +70,10 @@
],
"container": {
"hostname": "localhost",
"wait_delay": -1,
"seccomp_flags": 1,
"seccomp_presets": 1,
"seccomp_compat": true,
"devel": true,
"userns": true,
"net": true,
@ -109,10 +111,8 @@
}
],
"symlink": [
[
"/run/user/65534",
"/run/user/150"
]
"/run/user/65534",
"/run/user/150"
],
"etc": "/etc",
"auto_etc": true,
@ -120,4 +120,4 @@
"/var/run/nscd"
]
}
}
}

View File

@ -0,0 +1,2 @@
package app.hakurei.planterette.api.dsl

View File

@ -2,14 +2,6 @@ package buildsrc.convention
import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
kotlin("jvm")
}
kotlin {
jvmToolchain(21)
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()

19
cli/build.gradle.kts Normal file
View File

@ -0,0 +1,19 @@
plugins {
kotlin("jvm")
}
repositories {
mavenCentral()
}
dependencies {
implementation(project(":api"))
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(21)
}

View File

@ -1,6 +1,6 @@
plugins {
id("buildsrc.convention.kotlin-jvm")
kotlin("jvm")
application
}

View File

@ -0,0 +1,124 @@
{
"id": "org.debian",
"path": "/bin/bash",
"args": [
"bash"
],
"enablements": 13,
"session_bus": {
"see": null,
"talk": [
"org.freedesktop.Notifications",
"org.freedesktop.FileManager1",
"org.freedesktop.ScreenSaver"
],
"own": null,
"call": null,
"broadcast": null,
"filter": true
},
"system_bus": {
"see": null,
"talk": null,
"own": null,
"call": null,
"broadcast": null,
"filter": true
},
"username": "chronos",
"shell": "/bin/bash",
"data": "/tmp/chronos",
"dir": "/.hakurei/home",
"identity": 9,
"groups": null,
"container": {
"hostname": "debian",
"seccomp_flags": 0,
"seccomp_presets": 0,
"devel": true,
"userns": true,
"net": true,
"tty": true,
"multiarch": true,
"env": null,
"map_real_uid": true,
"filesystem": [
{
"dst": "/boot",
"src": "/mnt/debian/boot"
},
{
"dst": "/home",
"src": "/mnt/debian/home"
},
{
"dst": "/media",
"src": "/mnt/debian/media"
},
{
"dst": "/mnt",
"src": "/mnt/debian/mnt"
},
{
"dst": "/opt",
"src": "/mnt/debian/opt"
},
{
"dst": "/root",
"src": "/mnt/debian/root"
},
{
"dst": "/srv",
"src": "/mnt/debian/srv"
},
{
"dst": "/usr",
"src": "/mnt/debian/usr"
},
{
"dst": "/var",
"src": "/mnt/debian/var"
},
{
"src": "/sys/block"
},
{
"src": "/sys/bus"
},
{
"src": "/sys/class"
},
{
"src": "/sys/dev"
},
{
"src": "/sys/devices"
},
{
"src": "/dev/dri",
"dev": true
}
],
"symlink": [
[
"usr/bin",
"/bin"
],
[
"usr/lib",
"/lib"
],
[
"usr/lib64",
"/lib64"
],
[
"usr/sbin",
"/sbin"
]
],
"etc": "/mnt/debian/etc",
"auto_etc": false,
"cover": null
}
}

View File

@ -1,2 +1,3 @@
org.gradle.caching=true
org.gradle.configuration-cache=true
kotlin.mpp.applyDefaultHierarchyTemplate=false

View File

@ -1,17 +1,20 @@
[versions]
kotlin = "2.1.21"
kotlin = "2.2.0"
kotlinxDatetime = "0.6.1"
kotlinxSerializationJSON = "1.7.3"
kotlinxCoroutines = "1.9.0"
kotlinxIo = "0.8.0"
[libraries]
kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlinxDatetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
kotlinxSerialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJSON" }
kotlinxCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
kotlinxIo = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinxIo" }
[bundles]
kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines"]
kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines", "kotlinxIo"]
[plugins]
kotlinPluginSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlinPluginSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlinPluginMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }

20
gui/build.gradle.kts Normal file
View File

@ -0,0 +1,20 @@
plugins {
kotlin("jvm")
}
repositories {
mavenCentral()
}
dependencies {
implementation(project(":api"))
implementation(project(":cli"))
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(21)
}

View File

@ -9,7 +9,9 @@ plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
include(":app")
include(":daemon")
include(":api")
include(":cli")
include(":gui")
rootProject.name = "planterette"