kt-go-split #1
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,12 +1,14 @@ | ||||
| .gradle | ||||
| gradlew.bat | ||||
| build/ | ||||
| !gradle/wrapper/gradle-wrapper.jar | ||||
| !**/src/main/**/build/ | ||||
| !**/src/test/**/build/ | ||||
| 
 | ||||
| ### IntelliJ IDEA ### | ||||
| /.idea/ | ||||
| .idea/modules.xml | ||||
| .idea/jarRepositories.xml | ||||
| .idea/compiler.xml | ||||
| .idea/libraries/ | ||||
| *.iws | ||||
| *.iml | ||||
| *.ipr | ||||
|  | ||||
							
								
								
									
										2
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,5 +1,3 @@ | ||||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Environment-dependent path to Maven home directory | ||||
| /mavenHomeManager.xml | ||||
|  | ||||
							
								
								
									
										10
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| <component name="ProjectCodeStyleConfiguration"> | ||||
|   <code_scheme name="Project" version="173"> | ||||
|     <JetCodeStyleSettings> | ||||
|       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> | ||||
|     </JetCodeStyleSettings> | ||||
|     <codeStyleSettings language="kotlin"> | ||||
|       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> | ||||
|     </codeStyleSettings> | ||||
|   </code_scheme> | ||||
| </component> | ||||
							
								
								
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| <component name="ProjectCodeStyleConfiguration"> | ||||
|   <state> | ||||
|     <option name="USE_PER_PROJECT_SETTINGS" value="true" /> | ||||
|   </state> | ||||
| </component> | ||||
							
								
								
									
										8
									
								
								.idea/dictionaries/project.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								.idea/dictionaries/project.xml
									
									
									
										generated
									
									
									
								
							| @ -1,8 +0,0 @@ | ||||
| <component name="ProjectDictionaryState"> | ||||
|   <dictionary name="project"> | ||||
|     <words> | ||||
|       <w>buildsrc</w> | ||||
|       <w>planterette</w> | ||||
|     </words> | ||||
|   </dictionary> | ||||
| </component> | ||||
							
								
								
									
										18
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
								
							| @ -1,31 +1,13 @@ | ||||
| <?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$/buildSrc" /> | ||||
|             <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> | ||||
|  | ||||
							
								
								
									
										6
									
								
								.idea/kotlinc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/kotlinc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="KotlinJpsPluginSettings"> | ||||
|     <option name="version" value="2.2.10" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ExternalStorageConfigurationManager" enabled="true" /> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK"> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_24" default="true" project-jdk-name="openjdk-24" project-jdk-type="JavaSDK"> | ||||
|     <output url="file://$PROJECT_DIR$/out" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							| @ -1,23 +1,2 @@ | ||||
| # planterette | ||||
| 
 | ||||
| This project uses [Gradle](https://gradle.org/). | ||||
| To build and run the application, use the *Gradle* tool window by clicking the Gradle icon in the right-hand toolbar, | ||||
| or run it directly from the terminal: | ||||
| 
 | ||||
| * Run `./gradlew run` to build and run the application. | ||||
| * Run `./gradlew build` to only build the application. | ||||
| * Run `./gradlew check` to run all checks, including tests. | ||||
| * Run `./gradlew clean` to clean all build outputs. | ||||
| 
 | ||||
| Note the usage of the Gradle Wrapper (`./gradlew`). | ||||
| This is the suggested way to use Gradle in production projects. | ||||
| 
 | ||||
| [Learn more about the Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html). | ||||
| 
 | ||||
| [Learn more about Gradle tasks](https://docs.gradle.org/current/userguide/command_line_interface.html#common_tasks). | ||||
| 
 | ||||
| This project follows the suggested multi-module setup and consists of the `app` and `api` subprojects. | ||||
| The shared build logic was extracted to a convention plugin located in `buildSrc`. | ||||
| 
 | ||||
| This project uses a version catalog (see `gradle/libs.versions.toml`) to declare and version dependencies | ||||
| and both a build cache and a configuration cache (see `gradle.properties`). | ||||
							
								
								
									
										21
									
								
								build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| plugins { | ||||
|     kotlin("jvm") version "2.2.10" | ||||
| } | ||||
| 
 | ||||
| group = "moe.rosa" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| repositories { | ||||
|     mavenCentral() | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     testImplementation(kotlin("test")) | ||||
| } | ||||
| 
 | ||||
| tasks.test { | ||||
|     useJUnitPlatform() | ||||
| } | ||||
| kotlin { | ||||
|     jvmToolchain(24) | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| plugins { | ||||
|     `kotlin-dsl` | ||||
| } | ||||
| 
 | ||||
| kotlin { | ||||
|     jvmToolchain(24) | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     implementation(libs.kotlinGradlePlugin) | ||||
| } | ||||
| @ -1,15 +0,0 @@ | ||||
| dependencyResolutionManagement { | ||||
| 
 | ||||
|     @Suppress("UnstableApiUsage") | ||||
|     repositories { | ||||
|         mavenCentral() | ||||
|     } | ||||
| 
 | ||||
|     versionCatalogs { | ||||
|         create("libs") { | ||||
|             from(files("../gradle/libs.versions.toml")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| rootProject.name = "buildSrc" | ||||
| @ -1,15 +0,0 @@ | ||||
| package buildsrc.convention | ||||
| 
 | ||||
| import org.gradle.api.tasks.testing.logging.TestLogEvent | ||||
| 
 | ||||
| tasks.withType<Test>().configureEach { | ||||
|     useJUnitPlatform() | ||||
| 
 | ||||
|     testLogging { | ||||
|         events( | ||||
|             TestLogEvent.FAILED, | ||||
|             TestLogEvent.PASSED, | ||||
|             TestLogEvent.SKIPPED | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @ -1,3 +1 @@ | ||||
| org.gradle.caching=true | ||||
| org.gradle.configuration-cache=true | ||||
| kotlin.mpp.applyDefaultHierarchyTemplate=false | ||||
| kotlin.code.style=official | ||||
|  | ||||
| @ -1,20 +0,0 @@ | ||||
| [versions] | ||||
| 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", "kotlinxIo"] | ||||
| 
 | ||||
| [plugins] | ||||
| kotlinPluginSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } | ||||
| kotlinPluginMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } | ||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| #Tue Aug 26 23:15:20 CDT 2025 | ||||
| #Fri Sep 26 23:47:58 CDT 2025 | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip | ||||
|  | ||||
							
								
								
									
										43
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							| @ -15,8 +15,6 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| # SPDX-License-Identifier: Apache-2.0 | ||||
| # | ||||
| 
 | ||||
| ############################################################################## | ||||
| # | ||||
| @ -57,7 +55,7 @@ | ||||
| #       Darwin, MinGW, and NonStop. | ||||
| # | ||||
| #   (3) This script is generated from the Groovy template | ||||
| #       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt | ||||
| #       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt | ||||
| #       within the Gradle project. | ||||
| # | ||||
| #       You can find Gradle at https://github.com/gradle/gradle/. | ||||
| @ -82,11 +80,13 @@ do | ||||
|     esac | ||||
| done | ||||
| 
 | ||||
| # This is normally unused | ||||
| # shellcheck disable=SC2034 | ||||
| APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit | ||||
| 
 | ||||
| APP_NAME="Gradle" | ||||
| APP_BASE_NAME=${0##*/} | ||||
| # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) | ||||
| APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit | ||||
| 
 | ||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | ||||
| 
 | ||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||
| MAX_FD=maximum | ||||
| @ -133,29 +133,22 @@ location of your Java installation." | ||||
|     fi | ||||
| else | ||||
|     JAVACMD=java | ||||
|     if ! command -v java >/dev/null 2>&1 | ||||
|     then | ||||
|         die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
|     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| 
 | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
|     fi | ||||
| fi | ||||
| 
 | ||||
| # Increase the maximum file descriptors if we can. | ||||
| if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then | ||||
|     case $MAX_FD in #( | ||||
|       max*) | ||||
|         # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. | ||||
|         # shellcheck disable=SC2039,SC3045 | ||||
|         MAX_FD=$( ulimit -H -n ) || | ||||
|             warn "Could not query maximum file descriptor limit" | ||||
|     esac | ||||
|     case $MAX_FD in  #( | ||||
|       '' | soft) :;; #( | ||||
|       *) | ||||
|         # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. | ||||
|         # shellcheck disable=SC2039,SC3045 | ||||
|         ulimit -n "$MAX_FD" || | ||||
|             warn "Could not set maximum file descriptor limit to $MAX_FD" | ||||
|     esac | ||||
| @ -200,15 +193,11 @@ if "$cygwin" || "$msys" ; then | ||||
|     done | ||||
| fi | ||||
| 
 | ||||
| 
 | ||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | ||||
| 
 | ||||
| # Collect all arguments for the java command: | ||||
| #   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, | ||||
| #     and any embedded shellness will be escaped. | ||||
| #   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be | ||||
| #     treated as '${Hostname}' itself on the command line. | ||||
| # Collect all arguments for the java command; | ||||
| #   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of | ||||
| #     shell script including quotes and variable substitutions, so put them in | ||||
| #     double quotes to make sure that they get re-expanded; and | ||||
| #   * put everything else in single quotes, so that it's not re-expanded. | ||||
| 
 | ||||
| set -- \ | ||||
|         "-Dorg.gradle.appname=$APP_BASE_NAME" \ | ||||
| @ -216,12 +205,6 @@ set -- \ | ||||
|         org.gradle.wrapper.GradleWrapperMain \ | ||||
|         "$@" | ||||
| 
 | ||||
| # Stop when "xargs" is not available. | ||||
| if ! command -v xargs >/dev/null 2>&1 | ||||
| then | ||||
|     die "xargs is not available" | ||||
| fi | ||||
| 
 | ||||
| # Use "xargs" to parse quoted args. | ||||
| # | ||||
| # With -n1 it outputs one arg per line, with the quotes and backslashes removed. | ||||
|  | ||||
							
								
								
									
										89
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | ||||
| @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 | ||||
| @ -1,26 +0,0 @@ | ||||
| plugins { | ||||
|     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 = "libplt" | ||||
|         } | ||||
|     } | ||||
|     sourceSets { | ||||
|         commonMain.dependencies { | ||||
|             implementation(libs.bundles.kotlinxEcosystem) | ||||
|         } | ||||
|         commonTest.dependencies { | ||||
|             implementation(libs.bundles.kotlinxEcosystem) | ||||
|             implementation(kotlin("test")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,51 +0,0 @@ | ||||
| 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") | ||||
| @ -1,209 +0,0 @@ | ||||
| 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) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,35 +0,0 @@ | ||||
| package app.hakurei.planterette.api | ||||
| 
 | ||||
| import kotlinx.serialization.Serializable | ||||
| 
 | ||||
| @Serializable | ||||
| data class PackageManifest( | ||||
|     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) | ||||
| 
 | ||||
|     @Serializable | ||||
|     enum class Architecture { | ||||
|         X86_64, | ||||
|         ARM64, | ||||
|     } | ||||
|     @Serializable | ||||
|     data class BaseImage(val type: Type) { | ||||
|         @Serializable | ||||
|         enum class Type { | ||||
|             DEBIAN, | ||||
|             CHIMERA, | ||||
|         } | ||||
|     } | ||||
|     companion object { | ||||
|         val fileList = listOf("planterette.json", "icon.png", "image.tar") | ||||
|         val signatureFile = "package.sig" | ||||
|     } | ||||
| } | ||||
| @ -1,48 +0,0 @@ | ||||
| package app.hakurei.planterette.api | ||||
| 
 | ||||
| @Suppress("unused") | ||||
| object Paths { | ||||
|     const val FHS_ROOT = "/" | ||||
|     const val FHS_ETC = "/etc/" | ||||
|     const val FHS_TMP = "/tmp/" | ||||
| 
 | ||||
|     const val FHS_RUN = "/run/" | ||||
|     const val FHS_RUN_USER = FHS_RUN + "user/" | ||||
| 
 | ||||
|     const val FHS_USR = "/usr/" | ||||
|     const val FHS_USR_BIN = FHS_USR + "bin/" | ||||
| 
 | ||||
|     const val FHS_VAR = "/var/" | ||||
|     const val FHS_VAR_LIB = FHS_VAR + "lib/" | ||||
|     const val FHS_VAR_EMPTY = FHS_VAR + "empty/" | ||||
| 
 | ||||
|     const val FHS_DEV = "/dev/" | ||||
|     const val FHS_PROC = "/proc/" | ||||
|     const val FHS_PROC_SYS = FHS_PROC + "sys/" | ||||
|     const val FHS_SYS = "/sys/" | ||||
| 
 | ||||
|     const val NONEXISTENT = FHS_PROC + "nonexistent" | ||||
|     const val SYSROOT_DIR = "sysroot" | ||||
|     const val HOST_DIR = "host" | ||||
|     const val HOST_PATH = FHS_ROOT + HOST_DIR | ||||
|     const val SYSROOT_PATH = FHS_ROOT + SYSROOT_DIR | ||||
| 
 | ||||
|     val AbsFHSRoot = AbsolutePath(FHS_ROOT) | ||||
|     val AbsFHSEtc = AbsolutePath(FHS_ETC) | ||||
|     val AbsFHSTmp = AbsolutePath(FHS_TMP) | ||||
| 
 | ||||
|     val AbsFHSRun = AbsolutePath(FHS_RUN) | ||||
|     val AbsFHSRunUser = AbsolutePath(FHS_RUN_USER) | ||||
| 
 | ||||
|     val AbsFHSUsrBin = AbsolutePath(FHS_USR_BIN) | ||||
| 
 | ||||
|     val AbsFHSVar = AbsolutePath(FHS_VAR) | ||||
|     val AbsFHSVarLib = AbsolutePath(FHS_VAR_LIB) | ||||
| 
 | ||||
|     val AbsFHSDev = AbsolutePath(FHS_DEV) | ||||
|     val AbsFHSProc = AbsolutePath(FHS_PROC) | ||||
|     val AbsFHSSys = AbsolutePath(FHS_SYS) | ||||
| 
 | ||||
|     val AbsNonexistent = AbsolutePath(NONEXISTENT) | ||||
| } | ||||
| 
 | ||||
| @ -1,9 +0,0 @@ | ||||
| package app.hakurei.planterette.api | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
| @ -1,26 +0,0 @@ | ||||
| package app.hakurei.planterette.api | ||||
| 
 | ||||
| import kotlin.test.Test | ||||
| import kotlin.test.assertEquals | ||||
| import kotlin.test.assertFailsWith | ||||
| import kotlin.test.assertIs | ||||
| 
 | ||||
| class AbsolutePathTest { | ||||
|     @Test | ||||
|     fun testAbsolutePath() { | ||||
|         val path = AbsolutePath("/dev/null") | ||||
|         assertIs<AbsolutePath>(path) | ||||
|     } | ||||
|     @Test | ||||
|     fun testRelativePath() { | ||||
|         assertFailsWith(AbsolutePathException::class) { | ||||
|             AbsolutePath("./test") | ||||
|         } | ||||
|     } | ||||
|     @Test | ||||
|     fun testPathJoin() { | ||||
|         val want = AbsolutePath("/dev/null") | ||||
|         val base = AbsolutePath("/dev/") | ||||
|         assertEquals(want, base + "null") | ||||
|     } | ||||
| } | ||||
| @ -1,333 +0,0 @@ | ||||
| package app.hakurei.planterette.api | ||||
| 
 | ||||
| import app.hakurei.planterette.api.HakureiConfig.Enablement.* | ||||
| import app.hakurei.planterette.api.HakureiConfig.SeccompFilterPreset.* | ||||
| import app.hakurei.planterette.api.HakureiConfig.HakureiExportFlag.* | ||||
| import app.hakurei.planterette.api.HakureiConfig.RootFlag.* | ||||
| 
 | ||||
| import kotlinx.serialization.ExperimentalSerializationApi | ||||
| import kotlinx.serialization.encodeToString | ||||
| import kotlinx.serialization.json.Json | ||||
| 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() | ||||
|     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( | ||||
|             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/*"), | ||||
|             log = false, | ||||
|             filter = true, | ||||
|         ), | ||||
|         systemBus = HakureiConfig.DbusConfig( | ||||
|             talk = listOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"), | ||||
|             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(Multiarch), | ||||
|             seccompPresets = HakureiConfig.SeccompFilterPreset.filterPresets(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.FHS_RUN_USER + "150")), | ||||
|             autoRoot = Paths.AbsFHSVarLib + "hakurei/base/org.debian", | ||||
|             rootFlags = HakureiConfig.RootFlag.rootFlags(Writable), | ||||
|             etc = Paths.AbsFHSEtc, | ||||
|             autoEtc = true | ||||
|         ) | ||||
|     ) | ||||
| 
 | ||||
|     internal fun compare(want: HakureiConfig, test: HakureiConfig) { | ||||
|         assertEquals(want.id, test.id, "id") | ||||
| 
 | ||||
|         assertEquals(want.path, test.path, "path") | ||||
|         assertEquals(want.args, test.args, "args") | ||||
| 
 | ||||
|         assertEquals(want.enablements, test.enablements, "enablements") | ||||
| 
 | ||||
|         assertEquals(want.sessionBus?.see, test.sessionBus?.see, "sessionBus.see") | ||||
|         assertEquals(want.sessionBus?.talk, test.sessionBus?.talk, "sessionBus.talk") | ||||
|         assertEquals(want.sessionBus?.own, test.sessionBus?.own, "sessionBus.own") | ||||
|         assertEquals(want.sessionBus?.broadcast, test.sessionBus?.broadcast, "sessionBus.broadcast") | ||||
|         assertEquals(want.sessionBus?.log ?: false, test.sessionBus?.log, "sessionBus.log") | ||||
|         assertEquals(want.sessionBus?.filter, test.sessionBus?.filter, "sessionBus.filter") | ||||
| 
 | ||||
|         assertEquals(want.systemBus?.see, test.systemBus?.see, "systemBus.see") | ||||
|         assertEquals(want.systemBus?.talk, test.systemBus?.talk, "systemBus.talk") | ||||
|         assertEquals(want.systemBus?.own, test.systemBus?.own, "systemBus.own") | ||||
|         assertEquals(want.systemBus?.broadcast, test.systemBus?.broadcast, "systemBus.broadcast") | ||||
|         assertEquals(want.systemBus?.log ?: false, test.systemBus?.log, "systemBus.log") | ||||
|         assertEquals(want.systemBus?.filter, test.systemBus?.filter, "systemBus.filter") | ||||
| 
 | ||||
|         assertEquals(want.directWayland ?: false, test.directWayland, "directWayland") | ||||
|         assertEquals(want.username, test.username, "username") | ||||
|         assertEquals(want.shell, test.shell, "shell") | ||||
|         assertEquals(want.data, test.data, "data") | ||||
|         assertEquals(want.dir, test.dir, "dir") | ||||
|         assertEquals(want.extraPerms, test.extraPerms, "extraPerms") | ||||
| 
 | ||||
|         assertEquals(want.identity, test.identity, "identity") | ||||
|         assertEquals(want.groups, test.groups, "groups") | ||||
| 
 | ||||
|         assertEquals(want.container.waitDelay, test.container.waitDelay, "waitDelay") | ||||
|         assertEquals(want.container.seccompFlags, test.container.seccompFlags, "seccompFlags") | ||||
|         assertEquals(want.container.seccompPresets, test.container.seccompPresets, "seccompPresets") | ||||
|         assertEquals(want.container.seccompCompat, test.container.seccompCompat, "seccompCompat") | ||||
| 
 | ||||
|         assertEquals(want.container.devel, test.container.devel, "devel") | ||||
|         assertEquals(want.container.userns, test.container.userns, "userns") | ||||
|         assertEquals(want.container.net, test.container.net, "net") | ||||
|         assertEquals(want.container.tty, test.container.tty, "tty") | ||||
|         assertEquals(want.container.multiarch, test.container.multiarch, "multiarch") | ||||
| 
 | ||||
|         assertEquals(want.container.env, test.container.env, "env") | ||||
|         assertEquals(want.container.mapRealUid, test.container.mapRealUid, "mapRealUid") | ||||
| 
 | ||||
|         assertEquals(want.container.device, test.container.device, "device") | ||||
|         assertEquals(want.container.filesystem.size, test.container.filesystem.size, "filesystem.size") | ||||
|         for(i in 0 until want.container.filesystem.size) { | ||||
|             val w = want.container.filesystem[i] | ||||
|             val t = test.container.filesystem[i] | ||||
| 
 | ||||
|             assertEquals(w.src, t.src, "filesystem[$i].src") | ||||
|             assertEquals(w.dst, t.dst, "filesystem[$i].dst") | ||||
|             assertEquals(w.write, t.write, "filesystem[$i].write") | ||||
|             assertEquals(w.device, t.device, "filesystem[$i].device") | ||||
|             assertEquals(w.must, t.must, "filesystem[$i].must") | ||||
|         } | ||||
|         assertEquals(want.container.link, test.container.link, "link") | ||||
|         assertEquals(want.container.autoRoot, test.container.autoRoot, "autoroot") | ||||
| 
 | ||||
|         assertEquals(want.container.etc, test.container.etc, "etc") | ||||
| 
 | ||||
|         assertEquals(want.container.autoEtc, test.container.autoEtc, "autoEtc") | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun testHakureiConfigSerialization() { | ||||
|         val json = format.encodeToString(testConfig) | ||||
|         val test = format.decodeFromString<HakureiConfig>(json) | ||||
|         assertEquals(testConfig, test) | ||||
|         val want = format.decodeFromString<HakureiConfig>(want) | ||||
| 
 | ||||
|         compare(want, test) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun testEnablements() { | ||||
|         val enablement = HakureiConfig.Enablement.enablements(Wayland, X11, DBus, Pulse) | ||||
|         assertEquals(enablement, 0b1111) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun testSeccompFilterPresets() { | ||||
|         val presets = HakureiConfig.SeccompFilterPreset.filterPresets(Ext, DenyNS, DenyTTY, DenyDevel, Linux32) | ||||
|         assertEquals(presets, 0b11111) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun testExportFlags() { | ||||
|         val flags = HakureiConfig.HakureiExportFlag.exportFlags(Multiarch, CAN, Bluetooth) | ||||
|         assertEquals(flags, 0b111) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun testRootFlags() { | ||||
|         val flags = HakureiConfig.RootFlag.rootFlags(Optional, Writable, Device) | ||||
|         assertEquals(flags, 0b111) | ||||
|     } | ||||
| } | ||||
| @ -1,30 +0,0 @@ | ||||
| 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")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,16 +0,0 @@ | ||||
| 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()}" | ||||
| } | ||||
| @ -1,22 +0,0 @@ | ||||
| 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")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,22 +0,0 @@ | ||||
| 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")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,22 +0,0 @@ | ||||
| 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")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,18 +1,4 @@ | ||||
| dependencyResolutionManagement { | ||||
|     @Suppress("UnstableApiUsage") | ||||
|     repositories { | ||||
|         mavenCentral() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| plugins { | ||||
|     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" | ||||
| } | ||||
| 
 | ||||
| rootProject.name = "planterette" | ||||
| 
 | ||||
| include("plt") | ||||
| include("libplt") | ||||
| include("plt-build") | ||||
| include("plt-fetch") | ||||
| include("plt-pkg") | ||||
| rootProject.name = "planterette" | ||||
							
								
								
									
										5
									
								
								src/main/kotlin/moe/rosa/planterette/Main.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/main/kotlin/moe/rosa/planterette/Main.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| package moe.rosa.planterette | ||||
| 
 | ||||
| fun main() { | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user