mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
263 lines
7.8 KiB
Kotlin
263 lines
7.8 KiB
Kotlin
@file:OptIn(gobley.gradle.InternalGobleyGradleApi::class)
|
|
|
|
import gobley.gradle.cargo.dsl.appleMobile
|
|
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.RustAppleMobileTarget
|
|
import gobley.gradle.rust.targets.RustTarget
|
|
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.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)
|
|
}
|
|
|
|
// 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() ?: true
|
|
val diagnosticsEndpoint: String =
|
|
(findProperty("vnidrop.diagnostics.endpoint") as String?)?.trim().orEmpty()
|
|
val diagnosticsIngestKey: String =
|
|
(findProperty("vnidrop.diagnostics.ingestKey") as String?)?.trim().orEmpty()
|
|
check(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 = diagnosticsEndpoint
|
|
val ingestKey = diagnosticsIngestKey
|
|
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 {
|
|
if (GobleyHost.current.platform == GobleyHost.Platform.MacOS) {
|
|
listOf(
|
|
iosArm64(),
|
|
iosSimulatorArm64()
|
|
).forEach { iosTarget ->
|
|
iosTarget.binaries.framework {
|
|
baseName = "Shared"
|
|
isStatic = true
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
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)
|
|
if (GobleyHost.current.platform == GobleyHost.Platform.MacOS) {
|
|
addAll(RustAppleMobileTarget.entries)
|
|
}
|
|
}
|
|
|
|
cargo {
|
|
packageDirectory = layout.projectDirectory.dir("../crates/vnidrop")
|
|
publishJvmArtifacts = true
|
|
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.appleMobile {
|
|
variants {
|
|
buildTaskProvider.configure {
|
|
if (rustTarget.cinteropName == "ios") {
|
|
additionalEnvironment.put("IPHONEOS_DEPLOYMENT_TARGET", "16.0.0")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
builds.configureEach {
|
|
val buildOnCurrentHost = rustTarget in hostCargoTargets
|
|
installTargetBeforeBuild.set(buildOnCurrentHost)
|
|
variants {
|
|
buildTaskProvider.configure {
|
|
enabled = buildOnCurrentHost
|
|
}
|
|
checkTaskProvider.configure {
|
|
enabled = buildOnCurrentHost
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uniffi {
|
|
generateFromLibrary {
|
|
namespace = "vnidrop"
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|