restructure, begin implementing libplt
This commit is contained in:
parent
ae166bc45c
commit
ca586aaa36
9
.idea/gradle.xml
generated
9
.idea/gradle.xml
generated
@ -20,11 +20,12 @@
|
||||
<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" />
|
||||
<option value="$PROJECT_DIR$/libplt" />
|
||||
<option value="$PROJECT_DIR$/plt" />
|
||||
<option value="$PROJECT_DIR$/plt-build" />
|
||||
<option value="$PROJECT_DIR$/plt-fetch" />
|
||||
<option value="$PROJECT_DIR$/plt-pkg" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
@ -1,126 +0,0 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class HakureiConfig(
|
||||
val id: String,
|
||||
|
||||
val path: String? = null,
|
||||
val args: List<String>,
|
||||
|
||||
val enablements: Byte,
|
||||
|
||||
@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: List<ExtraPermConfig>?,
|
||||
|
||||
val identity: Int,
|
||||
val groups: List<String>,
|
||||
|
||||
val container: ContainerConfig
|
||||
) {
|
||||
@Serializable
|
||||
data class DbusConfig(
|
||||
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,
|
||||
val path: String,
|
||||
@SerialName("r") val read: Boolean? = null,
|
||||
@SerialName("w") val write: Boolean? = null,
|
||||
@SerialName("x") val execute: Boolean? = null
|
||||
)
|
||||
@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,
|
||||
|
||||
val devel: Boolean? = null,
|
||||
val userns: Boolean? = null,
|
||||
val net: Boolean? = null,
|
||||
val tty: Boolean? = null,
|
||||
val multiarch: Boolean? = null,
|
||||
|
||||
val env: Map<String, String>,
|
||||
@SerialName("map_real_uid") val mapRealUid: Boolean,
|
||||
|
||||
val device: Boolean? = null,
|
||||
val filesystem: List<FilesystemConfig>,
|
||||
@SerialName("symlink") val link: List<String>,
|
||||
|
||||
val etc: String? = null,
|
||||
@SerialName("auto_etc") val autoEtc: Boolean,
|
||||
val cover: List<String>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FilesystemConfig(
|
||||
val dst: String? = null,
|
||||
val src: String,
|
||||
val write: 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);
|
||||
|
||||
companion object {
|
||||
fun enablements(vararg enablements: Enablement): Byte {
|
||||
return enablements.sumOf(Enablement::value).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class SeccompFilterPreset(val value: Int) {
|
||||
Ext(1 shl 0),
|
||||
DenyNS(1 shl 1),
|
||||
DenyTTY(1 shl 2),
|
||||
DenyDevel(1 shl 3),
|
||||
Linux32(1 shl 4);
|
||||
|
||||
companion object {
|
||||
fun filterPresets(vararg filterPresets: SeccompFilterPreset): Int {
|
||||
return filterPresets.sumOf(SeccompFilterPreset::value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class HakureiExportFlag(val value: Int) {
|
||||
Multiarch(1 shl 0),
|
||||
CAN(1 shl 1),
|
||||
Bluetooth(1 shl 2);
|
||||
|
||||
companion object {
|
||||
fun exportFlags(vararg exportFlags: HakureiExportFlag): Int {
|
||||
return exportFlags.sumOf(HakureiExportFlag::value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.serializer
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class HakureiConfigTest {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
val format = Json {
|
||||
explicitNulls = false
|
||||
prettyPrint = true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHakureiConfigSerialization() {
|
||||
val testConfig = HakureiConfig(
|
||||
id = "org.chromium.Chromium",
|
||||
path = "/run/current-system/sw/bin/chromium",
|
||||
args = listOf(
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
),
|
||||
enablements = HakureiConfig.Enablement.enablements(HakureiConfig.Enablement.Wayland, HakureiConfig.Enablement.DBus,
|
||||
HakureiConfig.Enablement.Pulse),
|
||||
sessionBus = HakureiConfig.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 = HakureiConfig.DbusConfig(
|
||||
talk = listOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"),
|
||||
filter = true
|
||||
),
|
||||
|
||||
username = "chronos",
|
||||
shell = "/run/current-system/sw/bin/zsh",
|
||||
data = "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
dir = "/data/data/org.chromium.Chromium",
|
||||
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 = listOf("video", "dialout", "plugdev"),
|
||||
container = HakureiConfig.ContainerConfig(
|
||||
hostname = "localhost",
|
||||
devel = true,
|
||||
userns = true,
|
||||
net = true,
|
||||
device = true,
|
||||
seccompFlags = HakureiConfig.HakureiExportFlag.Multiarch.value,
|
||||
seccompPresets = HakureiConfig.SeccompFilterPreset.Ext.value,
|
||||
tty = true,
|
||||
multiarch = true,
|
||||
mapRealUid = true,
|
||||
env = mapOf(
|
||||
"GOOGLE_API_KEY" to "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||
"GOOGLE_DEFAULT_CLIENT_ID" to "77185425430.apps.googleusercontent.com",
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET" to "OTJgUOQcT7lO7GsGZq2G4IlT",
|
||||
),
|
||||
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 = "/dev/dri", device = true)
|
||||
),
|
||||
link = listOf("/run/user/65534", "/run/user/150"),
|
||||
etc = "/etc",
|
||||
autoEtc = true,
|
||||
cover = listOf("/var/run/nscd"),
|
||||
delay = -1,
|
||||
seccompCompat = true
|
||||
)
|
||||
)
|
||||
val json = format.encodeToString(serializer(), testConfig)
|
||||
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, "")
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
{
|
||||
"id": "org.chromium.Chromium",
|
||||
"path": "/run/current-system/sw/bin/chromium",
|
||||
"args": [
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
],
|
||||
"enablements": 13,
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"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.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"username": "chronos",
|
||||
"shell": "/run/current-system/sw/bin/zsh",
|
||||
"data": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
"dir": "/data/data/org.chromium.Chromium",
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/hakurei/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"identity": 9,
|
||||
"groups": [
|
||||
"video",
|
||||
"dialout",
|
||||
"plugdev"
|
||||
],
|
||||
"container": {
|
||||
"hostname": "localhost",
|
||||
"wait_delay": -1,
|
||||
"seccomp_flags": 1,
|
||||
"seccomp_presets": 1,
|
||||
"seccomp_compat": true,
|
||||
"devel": true,
|
||||
"userns": true,
|
||||
"net": true,
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"env": {
|
||||
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
||||
},
|
||||
"map_real_uid": true,
|
||||
"device": true,
|
||||
"filesystem": [
|
||||
{
|
||||
"src": "/nix/store"
|
||||
},
|
||||
{
|
||||
"src": "/run/current-system"
|
||||
},
|
||||
{
|
||||
"src": "/run/opengl-driver"
|
||||
},
|
||||
{
|
||||
"src": "/var/db/nix-channels"
|
||||
},
|
||||
{
|
||||
"dst": "/data/data/org.chromium.Chromium",
|
||||
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
"write": true,
|
||||
"require": true
|
||||
},
|
||||
{
|
||||
"src": "/dev/dri",
|
||||
"dev": true
|
||||
}
|
||||
],
|
||||
"symlink": [
|
||||
"/run/user/65534",
|
||||
"/run/user/150"
|
||||
],
|
||||
"etc": "/etc",
|
||||
"auto_etc": true,
|
||||
"cover": [
|
||||
"/var/run/nscd"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
package app.hakurei.planterette.api.dsl
|
||||
|
@ -1,19 +0,0 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":api"))
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
plugins {
|
||||
id("buildsrc.convention.kotlin-jvm")
|
||||
kotlin("jvm")
|
||||
application
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":api"))
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass = "app.hakurei.planterette.PlanteretteKt"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package app.hakurei.planterette
|
||||
|
||||
fun main() {
|
||||
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":api"))
|
||||
implementation(project(":cli"))
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
}
|
@ -11,7 +11,7 @@ kotlin {
|
||||
}
|
||||
nativeTarget.binaries {
|
||||
sharedLib {
|
||||
baseName = "planterette"
|
||||
baseName = "libplt"
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
@ -22,11 +22,5 @@ kotlin {
|
||||
implementation(libs.bundles.kotlinxEcosystem)
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
jvmMain.dependencies {
|
||||
|
||||
}
|
||||
jvmTest.dependencies {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
import app.hakurei.planterette.api.AbsolutePath.Companion.isAbsolute
|
||||
import kotlinx.io.files.Path
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
/**
|
||||
* 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(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(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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AbsolutePathException is returned by @see AbsolutePath() and holds the invalid pathname.
|
||||
*/
|
||||
data class AbsolutePathException(val pathname: String) : IllegalArgumentException("Path $pathname is not absolute")
|
@ -0,0 +1,209 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* HakureiConfig is used to seal an app implementation.
|
||||
* @param id reverse-DNS style arbitrary identifier string from config; Passed to wayland security-context-v1 as application ID and used as part of defaults in dbus session proxy
|
||||
*
|
||||
* @param path absolute path to executable file
|
||||
* @param args final args passed to container init
|
||||
*
|
||||
* @param enablements system services to make available in the container
|
||||
*
|
||||
* @param sessionBus session D-Bus proxy configuration; null makes session bus proxy assume built-in defaults
|
||||
* @param systemBus system D-Bus proxy configuration; null disables system bus proxy
|
||||
* @param directWayland direct access to the wayland socket; when this gets set no attempt is made to attach security-context-v1 and the bare socket is mounted to the sandbox
|
||||
*
|
||||
* @param username passwd username in container, defaults to passwd name of target uid or chronos
|
||||
* @param shell absolute path to shell
|
||||
* @param data absolute path to home directory in the init mount namespace
|
||||
* @param dir directory to ender and use as home in the container mount namespace, null for Data
|
||||
* @param extraPerms extra ACL ops, dispatches before container init
|
||||
*
|
||||
* @param identity numerical application id, used for init user namespace credentials
|
||||
* @param groups list of supplementary groups inherited by container processes
|
||||
*
|
||||
* @param container abstract container configuration baseline
|
||||
*/
|
||||
@Serializable
|
||||
data class HakureiConfig(
|
||||
val id: String,
|
||||
|
||||
val path: AbsolutePath? = null,
|
||||
val args: List<String>,
|
||||
|
||||
val enablements: Byte,
|
||||
|
||||
@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: AbsolutePath,
|
||||
val data: AbsolutePath,
|
||||
val dir: AbsolutePath,
|
||||
@SerialName("extra_perms") val extraPerms: List<ExtraPermConfig>? = null,
|
||||
|
||||
val identity: Int,
|
||||
val groups: List<String>,
|
||||
|
||||
val container: ContainerConfig
|
||||
) {
|
||||
@Serializable
|
||||
data class DbusConfig(
|
||||
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
|
||||
)
|
||||
|
||||
/**
|
||||
* ExtraPermConfig describes an ACL update op.
|
||||
*/
|
||||
@Serializable
|
||||
data class ExtraPermConfig(
|
||||
val ensure: Boolean? = null,
|
||||
val path: AbsolutePath,
|
||||
@SerialName("r") val read: Boolean? = null,
|
||||
@SerialName("w") val write: Boolean? = null,
|
||||
@SerialName("x") val execute: Boolean? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* ContainerConfig describes the container configuration baseline to which the app implementation adds upon.
|
||||
* @param hostname container hostname
|
||||
* @param waitDelay duration to wait for after interrupting a container's initial process in nanoseconds; a negative value causes the container to be terminated immediately on cancellation
|
||||
* @param seccompFlags extra seccomp flags
|
||||
* @param seccompPresets extra seccomp presets
|
||||
* @param seccompCompat disable project-specific filter extensions
|
||||
* @param devel allow ptrace and friends
|
||||
* @param userns allow userns creation in container
|
||||
* @param net share host net namespace
|
||||
* @param tty allow dangerous terminal I/O
|
||||
* @param multiarch allow multiarch
|
||||
*
|
||||
* @param env initial process environment variables
|
||||
* @param mapRealUid map target user uid to privileged user uid in the user namespace
|
||||
*
|
||||
* @param device pass through all devices
|
||||
* @param filesystem container host filesystem bind mounts
|
||||
* @param link create symlinks inside container filesystem
|
||||
*
|
||||
* @param autoRoot automatically bind mount top-level directories to container root; the zero value disables this behaviour
|
||||
* @param rootFlags extra flags for AutoRoot
|
||||
*
|
||||
* @param etc read-only /etc directory
|
||||
* @param autoEtc automatically set up /etc symlinks
|
||||
*/
|
||||
@Serializable
|
||||
data class ContainerConfig(
|
||||
val hostname: String?,
|
||||
@SerialName("wait_delay") val waitDelay: Int? = null,
|
||||
@SerialName("seccomp_flags") val seccompFlags: Int,
|
||||
@SerialName("seccomp_presets") val seccompPresets: Int,
|
||||
@SerialName("seccomp_compat") val seccompCompat: Boolean? = null,
|
||||
|
||||
val devel: Boolean? = null,
|
||||
val userns: Boolean? = null,
|
||||
val net: Boolean? = null,
|
||||
val tty: Boolean? = null,
|
||||
val multiarch: Boolean? = null,
|
||||
|
||||
val env: Map<String, String>,
|
||||
@SerialName("map_real_uid") val mapRealUid: Boolean,
|
||||
|
||||
val device: Boolean?,
|
||||
val filesystem: List<FilesystemConfig>,
|
||||
@SerialName("symlink") val link: List<LinkConfig>,
|
||||
|
||||
@SerialName("auto_root") val autoRoot: AbsolutePath,
|
||||
@SerialName("root_flags") val rootFlags: Int,
|
||||
|
||||
val etc: AbsolutePath?,
|
||||
|
||||
@SerialName("auto_etc") val autoEtc: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
* FilesystemConfig is an abstract representation of a bind mount.
|
||||
* @param dst mount point in container, same as src if empty
|
||||
* @param src host filesystem path to make available to the container
|
||||
* @param write do not mount filesystem read-only
|
||||
* @param device do not disable device files
|
||||
* @param must fail if the bind mount cannot be established for any reason
|
||||
*/
|
||||
@Serializable
|
||||
data class FilesystemConfig(
|
||||
val dst: AbsolutePath? = null,
|
||||
val src: AbsolutePath,
|
||||
val write: Boolean? = null,
|
||||
@SerialName("dev") val device: Boolean? = null,
|
||||
@SerialName("require") val must: Boolean? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* @param target symlink target in container
|
||||
* @param linkname linkname the symlink points to; prepend '*' to dereference an absolute pathname on host
|
||||
*/
|
||||
@Serializable
|
||||
data class LinkConfig(
|
||||
val target: AbsolutePath,
|
||||
val linkname: String
|
||||
)
|
||||
enum class Enablement(val value: Int) {
|
||||
Wayland(1 shl 0),
|
||||
X11(1 shl 1),
|
||||
DBus(1 shl 2),
|
||||
Pulse(1 shl 3);
|
||||
|
||||
companion object {
|
||||
fun enablements(vararg enablements: Enablement): Byte {
|
||||
return enablements.orOf(Enablement::value).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class SeccompFilterPreset(val value: Int) {
|
||||
Ext(1 shl 0),
|
||||
DenyNS(1 shl 1),
|
||||
DenyTTY(1 shl 2),
|
||||
DenyDevel(1 shl 3),
|
||||
Linux32(1 shl 4);
|
||||
|
||||
companion object {
|
||||
fun filterPresets(vararg filterPresets: SeccompFilterPreset): Int {
|
||||
return filterPresets.orOf(SeccompFilterPreset::value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class HakureiExportFlag(val value: Int) {
|
||||
Multiarch(1 shl 0),
|
||||
CAN(1 shl 1),
|
||||
Bluetooth(1 shl 2);
|
||||
|
||||
companion object {
|
||||
fun exportFlags(vararg exportFlags: HakureiExportFlag): Int {
|
||||
return exportFlags.orOf(HakureiExportFlag::value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class RootFlag(val value: Int) {
|
||||
Optional(1 shl 0),
|
||||
Writable(1 shl 1),
|
||||
Device(1 shl 2);
|
||||
|
||||
companion object {
|
||||
fun rootFlags(vararg rootFlags: RootFlag): Int {
|
||||
return rootFlags.orOf(RootFlag::value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,13 +4,13 @@ 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
|
||||
var hakureiConfig: HakureiConfig,
|
||||
var id: String,
|
||||
var version: Version,
|
||||
var name: String,
|
||||
var description: String,
|
||||
var architecture: MutableList<Architecture>,
|
||||
var baseImage: BaseImage
|
||||
) {
|
||||
@Serializable
|
||||
data class Version(val version: String, val canonicalVersion: UInt)
|
||||
@ -21,10 +21,12 @@ data class PackageManifest(
|
||||
ARM64,
|
||||
}
|
||||
@Serializable
|
||||
enum class BaseImage {
|
||||
DEBIAN,
|
||||
CHIMERA,
|
||||
|
||||
data class BaseImage(val type: Type) {
|
||||
@Serializable
|
||||
enum class Type {
|
||||
DEBIAN,
|
||||
CHIMERA,
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
val fileList = listOf("planterette.json", "icon.png", "image.tar")
|
@ -0,0 +1,47 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
object Paths {
|
||||
const val FHSRoot = "/"
|
||||
const val FHSEtc = "/etc/"
|
||||
const val FHSTmp = "/tmp/"
|
||||
|
||||
const val FHSRun = "/run/"
|
||||
const val FHSRunUser = FHSRun + "user/"
|
||||
|
||||
const val FHSUsr = "/usr/"
|
||||
const val FHSUsrBin = FHSUsr + "bin/"
|
||||
|
||||
const val FHSVar = "/var/"
|
||||
const val FHSVarLib = FHSVar + "lib/"
|
||||
const val FHSVarEmpty = FHSVar + "empty/"
|
||||
|
||||
const val FHSDev = "/dev/"
|
||||
const val FHSProc = "/proc/"
|
||||
const val FHSProcSys = FHSProc + "sys/"
|
||||
const val FHSSys = "/sys/"
|
||||
|
||||
const val Nonexistent = FHSProc + "nonexistent"
|
||||
const val sysrootDir = "sysroot"
|
||||
const val hostDir = "host"
|
||||
const val hostPath = FHSRoot + hostDir
|
||||
const val sysrootPath = FHSRoot + sysrootDir
|
||||
|
||||
val AbsFHSRoot = AbsolutePath(FHSRoot)
|
||||
val AbsFHSEtc = AbsolutePath(FHSEtc)
|
||||
val AbsFHSTmp = AbsolutePath(FHSTmp)
|
||||
|
||||
val AbsFHSRun = AbsolutePath(FHSRun)
|
||||
val AbsFHSRunUser = AbsolutePath(FHSRunUser)
|
||||
|
||||
val AbsFHSUsrBin = AbsolutePath(FHSUsrBin)
|
||||
|
||||
val AbsFHSVar = AbsolutePath(FHSVar)
|
||||
val AbsFHSVarLib = AbsolutePath(FHSVarLib)
|
||||
|
||||
val AbsFHSDev = AbsolutePath(FHSDev)
|
||||
val AbsFHSProc = AbsolutePath(FHSProc)
|
||||
val AbsFHSSys = AbsolutePath(FHSSys)
|
||||
|
||||
val AbsNonexistent = AbsolutePath(Nonexistent)
|
||||
}
|
||||
|
@ -14,3 +14,11 @@ object Util {
|
||||
return buffer.readString()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> Array<out T>.orOf(selector: (T) -> Int): Int {
|
||||
var sum = 0
|
||||
for (element in this) {
|
||||
sum = sum or selector(element)
|
||||
}
|
||||
return sum
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
import app.hakurei.planterette.api.HakureiConfig.Enablement.*
|
||||
import app.hakurei.planterette.api.HakureiConfig.RootFlag
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.serializer
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class HakureiConfigTest {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
val format = Json {
|
||||
explicitNulls = false
|
||||
prettyPrint = true
|
||||
}
|
||||
val want: String = """
|
||||
{
|
||||
"id": "org.chromium.Chromium",
|
||||
"path": "/run/current-system/sw/bin/chromium",
|
||||
"args": [
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
],
|
||||
"enablements": 13,
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"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.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"username": "chronos",
|
||||
"shell": "/run/current-system/sw/bin/zsh",
|
||||
"data": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
"dir": "/data/data/org.chromium.Chromium",
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/hakurei/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"identity": 9,
|
||||
"groups": [
|
||||
"video",
|
||||
"dialout",
|
||||
"plugdev"
|
||||
],
|
||||
"container": {
|
||||
"hostname": "localhost",
|
||||
"wait_delay": -1,
|
||||
"seccomp_flags": 1,
|
||||
"seccomp_presets": 1,
|
||||
"seccomp_compat": true,
|
||||
"devel": true,
|
||||
"userns": true,
|
||||
"net": true,
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"env": {
|
||||
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
||||
},
|
||||
"map_real_uid": true,
|
||||
"device": true,
|
||||
"filesystem": [
|
||||
{
|
||||
"dst": "/tmp/",
|
||||
"src": "/proc/nonexistent",
|
||||
"write": true
|
||||
},
|
||||
{
|
||||
"src": "/nix/store"
|
||||
},
|
||||
{
|
||||
"src": "/run/current-system"
|
||||
},
|
||||
{
|
||||
"src": "/run/opengl-driver"
|
||||
},
|
||||
{
|
||||
"src": "/var/db/nix-channels"
|
||||
},
|
||||
{
|
||||
"dst": "/data/data/org.chromium.Chromium",
|
||||
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||
"write": true,
|
||||
"require": true
|
||||
},
|
||||
{
|
||||
"src": "/dev/dri",
|
||||
"dev": true
|
||||
}
|
||||
],
|
||||
"symlink": [
|
||||
{
|
||||
"target": "/run/user/65534",
|
||||
"linkname": "/run/user/150"
|
||||
}
|
||||
],
|
||||
"auto_root": "/var/lib/hakurei/base/org.debian",
|
||||
"root_flags": 2,
|
||||
"etc": "/etc/",
|
||||
"auto_etc": true
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
@Test
|
||||
fun testHakureiConfigSerialization() {
|
||||
val testConfig = HakureiConfig(
|
||||
id = "org.chromium.Chromium",
|
||||
path = Paths.AbsFHSRun + "current-system/sw/bin/chromium",
|
||||
args = listOf(
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland",
|
||||
),
|
||||
enablements = HakureiConfig.Enablement.enablements(Wayland, DBus, Pulse),
|
||||
sessionBus = HakureiConfig.DbusConfig(
|
||||
see = null,
|
||||
talk = listOf("org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver"),
|
||||
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 = listOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"),
|
||||
own = null,
|
||||
call = null,
|
||||
broadcast = null,
|
||||
log = false,
|
||||
filter = true,
|
||||
),
|
||||
directWayland = false,
|
||||
|
||||
username = "chronos",
|
||||
shell = Paths.AbsFHSRun + "current-system/sw/bin/zsh",
|
||||
data = Paths.AbsFHSVarLib + "hakurei/u0/org.chromium.Chromium",
|
||||
dir = AbsolutePath("/data/data/org.chromium.Chromium"),
|
||||
extraPerms = listOf(
|
||||
HakureiConfig.ExtraPermConfig(path = Paths.AbsFHSVarLib + "hakurei/u0", ensure = true, execute = true),
|
||||
HakureiConfig.ExtraPermConfig(path = Paths.AbsFHSVarLib + "hakurei/u0/org.chromium.Chromium", read = true, write = true, execute = true)
|
||||
),
|
||||
identity = 9,
|
||||
groups = listOf("video", "dialout", "plugdev"),
|
||||
container = HakureiConfig.ContainerConfig(
|
||||
hostname = "localhost",
|
||||
devel = true,
|
||||
userns = true,
|
||||
net = true,
|
||||
device = true,
|
||||
waitDelay = -1,
|
||||
seccompFlags = HakureiConfig.HakureiExportFlag.exportFlags(HakureiConfig.HakureiExportFlag.Multiarch),
|
||||
seccompPresets = HakureiConfig.SeccompFilterPreset.filterPresets(HakureiConfig.SeccompFilterPreset.Ext),
|
||||
seccompCompat = true,
|
||||
tty = true,
|
||||
multiarch = true,
|
||||
mapRealUid = true,
|
||||
env = mapOf(
|
||||
"GOOGLE_API_KEY" to "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||
"GOOGLE_DEFAULT_CLIENT_ID" to "77185425430.apps.googleusercontent.com",
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET" to "OTJgUOQcT7lO7GsGZq2G4IlT"
|
||||
),
|
||||
filesystem = listOf(
|
||||
HakureiConfig.FilesystemConfig(dst = Paths.AbsFHSTmp, src = Paths.AbsNonexistent, write = true),
|
||||
HakureiConfig.FilesystemConfig(src = AbsolutePath("/nix/store")),
|
||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSRun + "current-system"),
|
||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSRun + "opengl-driver"),
|
||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSVar + "db/nix-channels"),
|
||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSVarLib + "hakurei/u0/org.chromium.Chromium", dst = AbsolutePath("/data/data/org.chromium.Chromium"), write = true, must = true),
|
||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSDev + "dri", device = true)
|
||||
),
|
||||
link = listOf(HakureiConfig.LinkConfig(Paths.AbsFHSRunUser + "65534", Paths.FHSRunUser + "150")),
|
||||
autoRoot = Paths.AbsFHSVarLib + "hakurei/base/org.debian",
|
||||
rootFlags = RootFlag.rootFlags(RootFlag.Writable),
|
||||
etc = Paths.AbsFHSEtc,
|
||||
autoEtc = true
|
||||
)
|
||||
)
|
||||
println("printing for now until a more proper test can be written")
|
||||
println(format.encodeToString(testConfig))
|
||||
}
|
||||
}
|
30
plt-build/build.gradle.kts
Normal file
30
plt-build/build.gradle.kts
Normal file
@ -0,0 +1,30 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
kotlin {
|
||||
jvm()
|
||||
val nativeTarget = if(System.getProperty("os.arch") == "aarch64") {
|
||||
linuxArm64("native")
|
||||
} else {
|
||||
linuxX64("native")
|
||||
}
|
||||
nativeTarget.binaries {
|
||||
executable()
|
||||
}
|
||||
sourceSets {
|
||||
nativeMain.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
}
|
||||
nativeTest.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
jvmMain.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
}
|
||||
jvmTest.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package app.hakurei.planterette.api
|
||||
|
||||
interface Task {
|
||||
val execute: String
|
||||
}
|
||||
class AptInstallTask(val packages: List<String>) : Task {
|
||||
private fun getPackageList(): String {
|
||||
var string = ""
|
||||
packages.forEach { p ->
|
||||
string += "$p "
|
||||
}
|
||||
return string
|
||||
}
|
||||
override val execute: String
|
||||
get() = "sudo apt install ${getPackageList()}"
|
||||
}
|
22
plt-fetch/build.gradle.kts
Normal file
22
plt-fetch/build.gradle.kts
Normal file
@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
kotlin {
|
||||
val nativeTarget = if(System.getProperty("os.arch") == "aarch64") {
|
||||
linuxArm64("native")
|
||||
} else {
|
||||
linuxX64("native")
|
||||
}
|
||||
nativeTarget.binaries {
|
||||
executable()
|
||||
}
|
||||
sourceSets {
|
||||
nativeMain.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
}
|
||||
nativeTest.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
22
plt-pkg/build.gradle.kts
Normal file
22
plt-pkg/build.gradle.kts
Normal file
@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
kotlin {
|
||||
val nativeTarget = if(System.getProperty("os.arch") == "aarch64") {
|
||||
linuxArm64("native")
|
||||
} else {
|
||||
linuxX64("native")
|
||||
}
|
||||
nativeTarget.binaries {
|
||||
executable()
|
||||
}
|
||||
sourceSets {
|
||||
nativeMain.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
}
|
||||
nativeTest.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
22
plt/build.gradle.kts
Normal file
22
plt/build.gradle.kts
Normal file
@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
kotlin {
|
||||
val nativeTarget = if(System.getProperty("os.arch") == "aarch64") {
|
||||
linuxArm64("native")
|
||||
} else {
|
||||
linuxX64("native")
|
||||
}
|
||||
nativeTarget.binaries {
|
||||
executable()
|
||||
}
|
||||
sourceSets {
|
||||
nativeMain.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
}
|
||||
nativeTest.dependencies {
|
||||
implementation(project(":libplt"))
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
@ -9,9 +9,10 @@ plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
||||
}
|
||||
|
||||
include(":daemon")
|
||||
include(":api")
|
||||
include(":cli")
|
||||
include(":gui")
|
||||
|
||||
rootProject.name = "planterette"
|
||||
|
||||
include("plt")
|
||||
include("libplt")
|
||||
include("plt-build")
|
||||
include("plt-fetch")
|
||||
include("plt-pkg")
|
Loading…
x
Reference in New Issue
Block a user