mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-30 07:37:38 +00:00
Quartz moves to its own repo, the way the crypto primitives moved to crypto-kmp. Every module depends on com.vitorpamplona.quartz:quartz 2.0.0 (libs.quartz) instead of :quartz, and -PquartzDir=../quartz builds a local checkout instead of the artifact, for every module and for quic's own quartz dependency (which replaces the root build's substitution of the published quartz with :quartz). What moved with quartz: its CI jobs (lint tasks, test-quartz-linux-native, test-quartz-ios), the Maven Central publish step of the release workflow, jitpack.yml, tools/unicode-nfkc, the nostr-expert and event-store-semantics skills, the agent-skill check, and the README's library usage docs. What stays here: - The four quartz client tests that need a real Ktor socket relay (TrustNetworkSync*, GiantReqStreamTest, BulkDownloadBenchmark) move to geode's tests; geode forwards -PprodRelayBench for the latter. quartz's other relay-client tests now use a test relay of its own, which ends quartz's test dependency on geode. - The benchmark module's resources (previously read from quartz's androidDeviceTest resources) move into benchmark/; relayBench --real reads the corpus from there. - NoteComposeKindCoverageTest reads EventFactory.kt from quartz's JVM sources jar, or from the -PquartzDir checkout, passed by commonsUI's build. - commons and commonsUI declare crypto-kmp (and commons mls-kmp), which they import directly. Through quartz's api alone, a -PcryptoKmpDir checkout never reached the common metadata compile. - The catalog drops what only quartz used (kchesslib, negentropy, jackson-databind, sqlite-bundled, secp256k1-kmp common, compose runtime-annotation, the maven-publish plugin). agent_config_check checks a skill's quartz/... paths against a ../quartz checkout when there is one and skips them otherwise. AGENTS.md, the skills, CONTRIBUTING, BUILDING, RELEASE_OPS, PLANS and the READMEs point at the new repo. Needs quartz 2.0.0 (and crypto-kmp 1.0.0) on Maven Central before CI can resolve it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEkJaDWYrcTbGvT8JLQCrG
83 lines
4.3 KiB
Kotlin
83 lines
4.3 KiB
Kotlin
// iOS purity gate shared by every KMP library module that targets Apple
|
|
// (`:commons`, `:commonsUI`). Apply it from the module's build
|
|
// script with
|
|
//
|
|
// apply(from = rootProject.file("gradle/kmp-purity.gradle.kts"))
|
|
//
|
|
// It registers `verifyKmpPurity` (wired into `check`) which fails when an
|
|
// iOS-targeted source set references a JVM-only API. `verifyKmpPurity` is the
|
|
// fast Linux pre-check that runs in the lint job; the macOS iOS compile job is
|
|
// the authoritative one. Keeping the pattern table in one file means a new
|
|
// forbidden API lands in every module at once instead of drifting per copy.
|
|
// vitorpamplona/quartz keeps a copy for :quartz: add a forbidden API to both.
|
|
|
|
val verifyKmpPurity = tasks.register("verifyKmpPurity") {
|
|
group = "verification"
|
|
description = "Fails if iOS-targeted source sets import JVM-only deps."
|
|
// Every source set that feeds an Apple target. Modules that don't have a
|
|
// given directory are skipped by the exists() filter, so the list is the
|
|
// union across modules (e.g. only :commonsUI has skikoMain today).
|
|
val checkedDirs =
|
|
listOf(
|
|
"src/commonMain", "src/commonTest",
|
|
"src/appleMain", "src/appleTest",
|
|
"src/nativeMain", "src/nativeTest",
|
|
"src/iosMain", "src/iosTest",
|
|
"src/skikoMain", "src/skikoTest",
|
|
"src/iosArm64Main", "src/iosArm64Test",
|
|
"src/iosSimulatorArm64Main", "src/iosSimulatorArm64Test",
|
|
"src/linuxMain", "src/linuxTest",
|
|
"src/linuxX64Main", "src/linuxX64Test",
|
|
"src/macosMain", "src/macosTest",
|
|
"src/macosArm64Main", "src/macosArm64Test",
|
|
).map { layout.projectDirectory.dir(it).asFile }
|
|
.filter { it.exists() }
|
|
inputs.files(checkedDirs)
|
|
doLast {
|
|
// Each pattern is paired with a short hint so the failure message
|
|
// points at the canonical KMP replacement.
|
|
val forbidden =
|
|
listOf(
|
|
"com.fasterxml.jackson" to "Jackson is JVM-only — use kotlinx.serialization",
|
|
"okhttp3" to "OkHttp is JVM-only — wrap behind expect/actual or use Ktor on iOS",
|
|
"System.currentTimeMillis" to "use TimeUtils.now()",
|
|
"Thread.sleep" to "use kotlinx.coroutines.delay or platform-specific actual",
|
|
"java.util.UUID" to "use kotlin.uuid.Uuid",
|
|
"kotlin.jvm.Synchronized" to "use a KMP lock primitive (KmpLock.withLock {} in commons)",
|
|
// The bare call, not just the annotation: `synchronized(lock) {}` resolves
|
|
// from kotlin-stdlib-jvm with no import, so it compiles on Android/JVM and
|
|
// only fails at the iOS compile step. Catch it here instead.
|
|
"synchronized(" to "`synchronized` is JVM-only — use a KMP lock primitive (KmpLock.withLock {} in commons)",
|
|
"kotlin.jvm.Volatile" to "use kotlin.concurrent.Volatile",
|
|
)
|
|
val offenders =
|
|
checkedDirs.flatMap { dir ->
|
|
dir
|
|
.walkTopDown()
|
|
.filter { it.isFile && it.extension == "kt" }
|
|
.flatMap { file ->
|
|
file.readLines().withIndex().mapNotNull { (idx, line) ->
|
|
val trimmed = line.trimStart()
|
|
// Skip KDoc / line-comment lines — those legitimately
|
|
// mention forbidden names (migration notes, doc refs).
|
|
if (trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*")) {
|
|
return@mapNotNull null
|
|
}
|
|
forbidden.firstOrNull { (pattern, _) -> line.contains(pattern) }?.let { (hit, hint) ->
|
|
"${file.relativeTo(rootDir)}:${idx + 1}: '$hit' — $hint"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (offenders.isNotEmpty()) {
|
|
throw GradleException(
|
|
"iOS-targeted source sets must not reference JVM-only APIs. " +
|
|
"Move the offending code to jvmAndroid/ or behind an expect/actual:\n " +
|
|
offenders.joinToString("\n "),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
tasks.named("check").configure { dependsOn(verifyKmpPurity) }
|