mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
261 lines
7.9 KiB
Kotlin
261 lines
7.9 KiB
Kotlin
@file:OptIn(gobley.gradle.InternalGobleyGradleApi::class)
|
|
|
|
import gobley.gradle.cargo.dsl.jvm
|
|
import gobley.gradle.cargo.tasks.CargoBuildTask
|
|
import gobley.gradle.cargo.tasks.CargoCheckTask
|
|
import gobley.gradle.GobleyHost
|
|
import gobley.gradle.rust.targets.RustAndroidTarget
|
|
import gobley.gradle.rust.targets.RustTarget
|
|
import gobley.gradle.Variant
|
|
import org.gradle.api.DefaultTask
|
|
import org.gradle.api.provider.ListProperty
|
|
import org.gradle.api.tasks.Input
|
|
import org.gradle.api.tasks.PathSensitivity
|
|
import org.gradle.api.tasks.TaskAction
|
|
import org.gradle.jvm.tasks.Jar
|
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
|
|
abstract class VerifyHostCargoTaskSelection : DefaultTask() {
|
|
@get:Input
|
|
abstract val mismatches: ListProperty<String>
|
|
|
|
@TaskAction
|
|
fun verify() {
|
|
check(mismatches.get().isEmpty()) {
|
|
"Cargo tasks do not match the current host: ${mismatches.get().joinToString()}"
|
|
}
|
|
}
|
|
}
|
|
|
|
plugins {
|
|
alias(libs.plugins.kotlinMultiplatform)
|
|
alias(libs.plugins.androidLibrary)
|
|
alias(libs.plugins.composeMultiplatform)
|
|
alias(libs.plugins.composeCompiler)
|
|
alias(libs.plugins.gobleyCargo)
|
|
alias(libs.plugins.gobleyUniffi)
|
|
alias(libs.plugins.kotlinAtomicfu)
|
|
}
|
|
|
|
val appVersion = providers.gradleProperty("vnidrop.version").get()
|
|
val desktopRustVariant = providers.gradleProperty("vnidrop.desktop.rustVariant")
|
|
.map { value ->
|
|
when (value.trim().lowercase()) {
|
|
"debug" -> Variant.Debug
|
|
"release" -> Variant.Release
|
|
else -> error("vnidrop.desktop.rustVariant must be either debug or release")
|
|
}
|
|
}
|
|
.orElse(Variant.Debug)
|
|
|
|
// Compile-time switches (gradle.properties or -P…).
|
|
// included=false: no Share-diagnostics toggle, no telemetry/crash auto-upload stack.
|
|
// endpoint/key both empty: transport is NoOp (safe default until Cloudflare is deployed).
|
|
val diagnosticsIncluded: Boolean =
|
|
(findProperty("vnidrop.diagnostics.included") as String?)?.toBooleanStrictOrNull() ?: false
|
|
val diagnosticsEndpoint: String =
|
|
(findProperty("vnidrop.diagnostics.endpoint") as String?)?.trim().orEmpty()
|
|
val diagnosticsIngestKey: String =
|
|
(findProperty("vnidrop.diagnostics.ingestKey") as String?)?.trim().orEmpty()
|
|
check(!diagnosticsIncluded || diagnosticsEndpoint.isEmpty() == diagnosticsIngestKey.isEmpty()) {
|
|
"vnidrop.diagnostics.endpoint and vnidrop.diagnostics.ingestKey must be configured together"
|
|
}
|
|
|
|
val diagnosticsBuildConfigDir = layout.buildDirectory.dir("generated/diagnostics/commonMain/kotlin")
|
|
val generateDiagnosticsBuildConfig by tasks.registering {
|
|
group = "build"
|
|
description = "Generates DiagnosticsBuildConfig from vnidrop.diagnostics.* properties"
|
|
val outputDir = diagnosticsBuildConfigDir
|
|
val included = diagnosticsIncluded
|
|
val endpoint = if (included) diagnosticsEndpoint else ""
|
|
val ingestKey = if (included) diagnosticsIngestKey else ""
|
|
inputs.property("vnidrop.diagnostics.included", included)
|
|
inputs.property("vnidrop.diagnostics.endpoint", endpoint)
|
|
inputs.property("vnidrop.diagnostics.ingestKey", ingestKey)
|
|
outputs.dir(outputDir)
|
|
doLast {
|
|
val packageDir = outputDir.get().asFile.resolve("com/vnidrop/app/diagnostics")
|
|
packageDir.mkdirs()
|
|
fun esc(value: String): String = buildString {
|
|
for (ch in value) {
|
|
when (ch) {
|
|
'\\' -> append("\\\\")
|
|
'"' -> append("\\\"")
|
|
'\n' -> append("\\n")
|
|
'\r' -> append("\\r")
|
|
'\t' -> append("\\t")
|
|
'$' -> append("\\$")
|
|
else -> append(ch)
|
|
}
|
|
}
|
|
}
|
|
packageDir.resolve("DiagnosticsBuildConfig.kt").writeText(
|
|
"""
|
|
|package com.vnidrop.app.diagnostics
|
|
|
|
|
|/**
|
|
| * Generated by shared/build.gradle.kts from vnidrop.diagnostics.* properties.
|
|
| *
|
|
| * - included=false → no opt-in UI / telemetry / crash hooks
|
|
| * - endpoint/key both empty → [NoOpDiagnosticsTransport] (no network)
|
|
| */
|
|
|object DiagnosticsBuildConfig {
|
|
| const val INCLUDED: Boolean = $included
|
|
| const val ENDPOINT: String = "${esc(endpoint)}"
|
|
| const val INGEST_KEY: String = "${esc(ingestKey)}"
|
|
|}
|
|
|
|
|
""".trimMargin(),
|
|
)
|
|
}
|
|
}
|
|
|
|
kotlin {
|
|
androidTarget {
|
|
compilerOptions {
|
|
jvmTarget = JvmTarget.JVM_11
|
|
}
|
|
}
|
|
|
|
jvm()
|
|
|
|
sourceSets {
|
|
commonMain {
|
|
kotlin.srcDir(files(diagnosticsBuildConfigDir).builtBy(generateDiagnosticsBuildConfig))
|
|
}
|
|
androidMain.dependencies {
|
|
implementation(libs.androidx.activity.compose)
|
|
implementation(libs.androidx.core.ktx)
|
|
implementation(libs.google.code.scanner)
|
|
implementation(libs.compose.uiToolingPreview)
|
|
}
|
|
jvmMain.dependencies {
|
|
implementation(libs.filekit.dialogs)
|
|
implementation(libs.jna.platform)
|
|
}
|
|
commonMain.dependencies {
|
|
implementation(libs.compose.runtime)
|
|
implementation(libs.compose.foundation)
|
|
implementation(libs.compose.material3)
|
|
implementation(libs.compose.ui)
|
|
implementation(libs.compose.components.resources)
|
|
implementation(libs.compose.uiToolingPreview)
|
|
implementation(libs.androidx.lifecycle.viewmodelCompose)
|
|
implementation(libs.androidx.lifecycle.runtimeCompose)
|
|
implementation(libs.androidx.datastore)
|
|
implementation(libs.androidx.datastore.preferences)
|
|
implementation(libs.kotlinx.coroutinesCore)
|
|
implementation(libs.qrcode.kotlin)
|
|
}
|
|
commonTest.dependencies {
|
|
implementation(libs.kotlin.test)
|
|
implementation(libs.kotlinx.coroutinesTest)
|
|
}
|
|
jvmTest.dependencies {
|
|
implementation(compose.desktop.currentOs)
|
|
implementation(libs.compose.uiTest)
|
|
}
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
debugImplementation(libs.compose.uiTooling)
|
|
}
|
|
|
|
android {
|
|
namespace = "com.vnidrop.app.shared"
|
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
|
|
|
defaultConfig {
|
|
minSdk = libs.versions.android.minSdk.get().toInt()
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_11
|
|
targetCompatibility = JavaVersion.VERSION_11
|
|
}
|
|
}
|
|
|
|
val hostCargoTargets = buildSet<RustTarget> {
|
|
add(GobleyHost.current.rustTarget)
|
|
addAll(RustAndroidTarget.entries)
|
|
}
|
|
|
|
cargo {
|
|
packageDirectory = layout.projectDirectory.dir("../crates/vnidrop")
|
|
publishJvmArtifacts = true
|
|
jvmVariant.set(desktopRustVariant)
|
|
androidTargetsToBuild.set(setOf(RustAndroidTarget.Arm64, RustAndroidTarget.X64))
|
|
builds.jvm {
|
|
variants {
|
|
// Desktop distributions are built per host. Do not publish disabled
|
|
// cross-platform native jars into the app runtime classpath.
|
|
embedRustLibrary.set(rustTarget == GobleyHost.current.rustTarget)
|
|
}
|
|
}
|
|
builds.configureEach {
|
|
val buildOnCurrentHost = rustTarget in hostCargoTargets
|
|
installTargetBeforeBuild.set(buildOnCurrentHost)
|
|
variants {
|
|
buildTaskProvider.configure {
|
|
enabled = buildOnCurrentHost
|
|
}
|
|
checkTaskProvider.configure {
|
|
enabled = buildOnCurrentHost
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uniffi {
|
|
generateFromLibrary {
|
|
namespace = "vnidrop"
|
|
build.set(GobleyHost.current.rustTarget)
|
|
variant.set(desktopRustVariant)
|
|
}
|
|
}
|
|
|
|
tasks.named<Jar>("jvmJar") {
|
|
manifest.attributes["Implementation-Version"] = appVersion
|
|
}
|
|
|
|
val verifyHostCargoTaskSelection = tasks.register<VerifyHostCargoTaskSelection>(
|
|
"verifyHostCargoTaskSelection"
|
|
) {
|
|
group = "verification"
|
|
description = "Verifies that Cargo tasks are enabled only for targets supported by this host."
|
|
mismatches.convention(emptyList())
|
|
}
|
|
|
|
afterEvaluate {
|
|
verifyHostCargoTaskSelection.configure {
|
|
mismatches.set(buildList {
|
|
tasks.withType<CargoBuildTask>().forEach {
|
|
if (it.enabled != (it.target.get() in hostCargoTargets)) add(it.path)
|
|
}
|
|
tasks.withType<CargoCheckTask>().forEach {
|
|
if (it.enabled != (it.target.get() in hostCargoTargets)) add(it.path)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
tasks.named("check") {
|
|
dependsOn(verifyHostCargoTaskSelection)
|
|
}
|
|
|
|
tasks.configureEach {
|
|
// Gobley does not currently treat every Rust source/API change as an input of
|
|
// all platform cargo tasks. Without these inputs an incremental Android build
|
|
// can package an older .so next to freshly generated UniFFI Kotlin bindings.
|
|
if (name.startsWith("cargoBuild")) {
|
|
inputs.files(
|
|
fileTree(layout.projectDirectory.dir("../crates/vnidrop")) {
|
|
include("Cargo.toml", "build.rs", "src/**/*.rs")
|
|
},
|
|
layout.projectDirectory.file("../Cargo.toml"),
|
|
layout.projectDirectory.file("../Cargo.lock"),
|
|
).withPathSensitivity(PathSensitivity.RELATIVE)
|
|
}
|
|
}
|