diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e9912bc8..82b9780e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,9 +16,9 @@ jobs: matrix: include: - os: macos-latest - targets: iosSimulatorArm64Test jvmTest lintKotlin + targets: iosSimulatorArm64Test macosArm64Test jvmTest - os: ubuntu-latest - targets: testDebugUnitTest testReleaseUnitTest jvmTest + targets: testDebugUnitTest testReleaseUnitTest jvmTest lintKotlin - os: windows-latest targets: jvmTest runs-on: ${{ matrix.os }} diff --git a/PowerSyncKotlin/build.gradle.kts b/PowerSyncKotlin/build.gradle.kts index 09eb3e5b..8d069221 100644 --- a/PowerSyncKotlin/build.gradle.kts +++ b/PowerSyncKotlin/build.gradle.kts @@ -17,6 +17,8 @@ kotlin { iosX64(), iosArm64(), iosSimulatorArm64(), + macosArm64(), + macosX64(), ).forEach { it.binaries.framework { export(project(":core")) @@ -41,6 +43,26 @@ kotlin { } } +repositories { + maven { + name = "PowerSyncSQLiterFork" + url = uri("https://powersync-ja.github.io/SQLiter") + content { + includeModuleByRegex("co.touchlab", "sqliter-driver.*") + } + } +} + +configurations.all { + resolutionStrategy { + // This version has not been released yet (https://github.com/touchlab/SQLiter/pull/124), so we're pointing this + // towards our fork with the repositories block above. + // The API is identical, but we have to make sure this particular project builds the xcframework with the + // patched SQLiter version to avoid linker errors on macOS. + force("co.touchlab:sqliter-driver:1.3.2-powersync") + } +} + kmmbridge { artifactManager.set(SonatypePortalPublishArtifactManager(project, repositoryName = null)) artifactManager.finalizeValue() diff --git a/PowerSyncKotlin/src/iosMain/kotlin/com/powersync/SDK.kt b/PowerSyncKotlin/src/appleMain/kotlin/com/powersync/SDK.kt similarity index 100% rename from PowerSyncKotlin/src/iosMain/kotlin/com/powersync/SDK.kt rename to PowerSyncKotlin/src/appleMain/kotlin/com/powersync/SDK.kt diff --git a/compose/build.gradle.kts b/compose/build.gradle.kts index c6dbcbb4..dd16112c 100644 --- a/compose/build.gradle.kts +++ b/compose/build.gradle.kts @@ -1,4 +1,5 @@ import com.powersync.plugins.sonatype.setupGithubRepository +import com.powersync.plugins.utils.powersyncTargets plugins { alias(libs.plugins.kotlinMultiplatform) @@ -10,15 +11,7 @@ plugins { } kotlin { - androidTarget { - publishLibraryVariants("release", "debug") - } - - jvm() - - iosX64() - iosArm64() - iosSimulatorArm64() + powersyncTargets(includeTargetsWithoutComposeSupport = false) explicitApi() diff --git a/connectors/supabase/build.gradle.kts b/connectors/supabase/build.gradle.kts index fb1f282e..984d62b6 100644 --- a/connectors/supabase/build.gradle.kts +++ b/connectors/supabase/build.gradle.kts @@ -1,4 +1,5 @@ import com.powersync.plugins.sonatype.setupGithubRepository +import com.powersync.plugins.utils.powersyncTargets import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { @@ -10,12 +11,7 @@ plugins { } kotlin { - androidTarget { - publishLibraryVariants("release", "debug") - } - - jvm() - + powersyncTargets() targets.withType { compilations.named("main") { compileTaskProvider { @@ -24,10 +20,6 @@ kotlin { } } - iosX64() - iosArm64() - iosSimulatorArm64() - explicitApi() sourceSets { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index fd5ab33c..802ecf0b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,9 +1,8 @@ import com.powersync.plugins.sonatype.setupGithubRepository +import com.powersync.plugins.utils.powersyncTargets import de.undercouch.gradle.tasks.download.Download import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.internal.os.OperatingSystem -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest @@ -84,15 +83,22 @@ val downloadPowersyncFramework by tasks.registering(Download::class) { onlyIfModified(true) } -val unzipPowersyncFramework by tasks.registering(Copy::class) { +val unzipPowersyncFramework by tasks.registering(Exec::class) { dependsOn(downloadPowersyncFramework) - from( - zipTree(downloadPowersyncFramework.get().dest).matching { - include("powersync-sqlite-core.xcframework/**") - }, - ) - into(binariesFolder.map { it.dir("framework") }) + val zipfile = downloadPowersyncFramework.get().dest + inputs.file(zipfile) + val destination = File(zipfile.parentFile, "extracted") + doFirst { + destination.deleteRecursively() + destination.mkdir() + } + + // We're using unzip here because the Gradle copy task doesn't support symlinks. + executable = "unzip" + args(zipfile.absolutePath) + workingDir(destination) + outputs.dir(destination) } val sqliteJDBCFolder = @@ -150,26 +156,7 @@ val moveJDBCJNIFiles by tasks.registering(Copy::class) { } kotlin { - androidTarget { - publishLibraryVariants("release", "debug") - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } - } - jvm { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) - // https://jakewharton.com/kotlins-jdk-release-compatibility-flag/ - freeCompilerArgs.add("-Xjdk-release=8") - } - } - - iosX64() - iosArm64() - iosSimulatorArm64() + powersyncTargets() targets.withType { compilations.named("main") { @@ -184,7 +171,20 @@ kotlin { linkerOpts("-framework", "powersync-sqlite-core") val frameworkRoot = binariesFolder - .map { it.dir("framework/powersync-sqlite-core.xcframework/ios-arm64_x86_64-simulator") } + .map { it.dir("framework/extracted/powersync-sqlite-core.xcframework/ios-arm64_x86_64-simulator") } + .get() + .asFile.path + + linkerOpts("-F", frameworkRoot) + linkerOpts("-rpath", frameworkRoot) + } + } else if (konanTarget.family == Family.OSX) { + binaries.withType().configureEach { + linkTaskProvider.configure { dependsOn(unzipPowersyncFramework) } + linkerOpts("-framework", "powersync-sqlite-core") + var frameworkRoot = + binariesFolder + .map { it.dir("framework/extracted/powersync-sqlite-core.xcframework/macos-arm64_x86_64") } .get() .asFile.path @@ -253,8 +253,8 @@ kotlin { } } - iosMain.dependencies { - implementation(libs.ktor.client.ios) + appleMain.dependencies { + implementation(libs.ktor.client.darwin) } commonTest.dependencies { @@ -271,8 +271,9 @@ kotlin { // tests. jvmTest.get().dependsOn(commonIntegrationTest) - // We're linking the xcframework for the simulator tests, so they can use integration tests too - iosSimulatorArm64Test.orNull?.dependsOn(commonIntegrationTest) + // We have special setup in this build configuration to make these tests link the PowerSync extension, so they + // can run integration tests along with the executable for unit testing. + appleTest.orNull?.dependsOn(commonIntegrationTest) } } diff --git a/core/src/iosMain/kotlin/BuildConfig.kt b/core/src/appleMain/kotlin/BuildConfig.kt similarity index 100% rename from core/src/iosMain/kotlin/BuildConfig.kt rename to core/src/appleMain/kotlin/BuildConfig.kt diff --git a/core/src/iosMain/kotlin/com/powersync/DatabaseDriverFactory.ios.kt b/core/src/appleMain/kotlin/com/powersync/DatabaseDriverFactory.ios.kt similarity index 100% rename from core/src/iosMain/kotlin/com/powersync/DatabaseDriverFactory.ios.kt rename to core/src/appleMain/kotlin/com/powersync/DatabaseDriverFactory.ios.kt diff --git a/core/src/iosMain/kotlin/com/powersync/DeferredDriver.kt b/core/src/appleMain/kotlin/com/powersync/DeferredDriver.kt similarity index 100% rename from core/src/iosMain/kotlin/com/powersync/DeferredDriver.kt rename to core/src/appleMain/kotlin/com/powersync/DeferredDriver.kt diff --git a/core/src/iosSimulatorArm64Test/kotlin/com/powersync/DatabaseDriverFactoryTest.kt b/core/src/appleTest/kotlin/com/powersync/DatabaseDriverFactoryTest.kt similarity index 100% rename from core/src/iosSimulatorArm64Test/kotlin/com/powersync/DatabaseDriverFactoryTest.kt rename to core/src/appleTest/kotlin/com/powersync/DatabaseDriverFactoryTest.kt diff --git a/core/src/iosSimulatorArm64Test/kotlin/com/powersync/testutils/TestUtils.iosSimulatorArm64.kt b/core/src/appleTest/kotlin/com/powersync/testutils/TestUtils.apple.kt similarity index 100% rename from core/src/iosSimulatorArm64Test/kotlin/com/powersync/testutils/TestUtils.iosSimulatorArm64.kt rename to core/src/appleTest/kotlin/com/powersync/testutils/TestUtils.apple.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f608d95f..666359ea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -59,6 +59,7 @@ kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } kermit-test = { module = "co.touchlab:kermit-test", version.ref = "kermit" } powersync-sqlite-core-android = { module = "co.powersync:powersync-sqlite-core", version.ref = "powersync-core" } mavenPublishPlugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "maven-publish" } +kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } test-junit = { group = "junit", name = "junit", version.ref = "junit" } test-android-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" } @@ -76,7 +77,7 @@ kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version. uuid = { module = "com.benasher44:uuid", version.ref = "uuid" } ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } -ktor-client-ios = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } +ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-contentnegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" } diff --git a/persistence/build.gradle.kts b/persistence/build.gradle.kts index 3caabf3a..69eaafb8 100644 --- a/persistence/build.gradle.kts +++ b/persistence/build.gradle.kts @@ -1,4 +1,5 @@ import com.powersync.plugins.sonatype.setupGithubRepository +import com.powersync.plugins.utils.powersyncTargets import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget @@ -11,27 +12,7 @@ plugins { } kotlin { - androidTarget { - publishLibraryVariants("release", "debug") - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } - } - - jvm { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) - // https://jakewharton.com/kotlins-jdk-release-compatibility-flag/ - freeCompilerArgs.add("-Xjdk-release=8") - } - } - - iosX64() - iosArm64() - iosSimulatorArm64() + powersyncTargets() explicitApi() @@ -49,7 +30,7 @@ kotlin { api(libs.sqldelight.driver.jdbc) } - iosMain.dependencies { + appleMain.dependencies { api(libs.sqldelight.driver.native) api(projects.staticSqliteDriver) } diff --git a/persistence/src/iosMain/kotlin/com/powersync/persistence/driver/Borrowed.kt b/persistence/src/appleMain/kotlin/com/powersync/persistence/driver/Borrowed.kt similarity index 100% rename from persistence/src/iosMain/kotlin/com/powersync/persistence/driver/Borrowed.kt rename to persistence/src/appleMain/kotlin/com/powersync/persistence/driver/Borrowed.kt diff --git a/persistence/src/iosMain/kotlin/com/powersync/persistence/driver/NativeSqlDatabase.kt b/persistence/src/appleMain/kotlin/com/powersync/persistence/driver/NativeSqlDatabase.kt similarity index 100% rename from persistence/src/iosMain/kotlin/com/powersync/persistence/driver/NativeSqlDatabase.kt rename to persistence/src/appleMain/kotlin/com/powersync/persistence/driver/NativeSqlDatabase.kt diff --git a/persistence/src/iosMain/kotlin/com/powersync/persistence/driver/Pool.kt b/persistence/src/appleMain/kotlin/com/powersync/persistence/driver/Pool.kt similarity index 100% rename from persistence/src/iosMain/kotlin/com/powersync/persistence/driver/Pool.kt rename to persistence/src/appleMain/kotlin/com/powersync/persistence/driver/Pool.kt diff --git a/persistence/src/iosMain/kotlin/com/powersync/persistence/driver/SqliterSqlCursor.kt b/persistence/src/appleMain/kotlin/com/powersync/persistence/driver/SqliterSqlCursor.kt similarity index 100% rename from persistence/src/iosMain/kotlin/com/powersync/persistence/driver/SqliterSqlCursor.kt rename to persistence/src/appleMain/kotlin/com/powersync/persistence/driver/SqliterSqlCursor.kt diff --git a/persistence/src/iosMain/kotlin/com/powersync/persistence/driver/SqliterStatement.kt b/persistence/src/appleMain/kotlin/com/powersync/persistence/driver/SqliterStatement.kt similarity index 100% rename from persistence/src/iosMain/kotlin/com/powersync/persistence/driver/SqliterStatement.kt rename to persistence/src/appleMain/kotlin/com/powersync/persistence/driver/SqliterStatement.kt diff --git a/persistence/src/iosMain/kotlin/com/powersync/persistence/driver/util/PoolLock.kt b/persistence/src/appleMain/kotlin/com/powersync/persistence/driver/util/PoolLock.kt similarity index 100% rename from persistence/src/iosMain/kotlin/com/powersync/persistence/driver/util/PoolLock.kt rename to persistence/src/appleMain/kotlin/com/powersync/persistence/driver/util/PoolLock.kt diff --git a/plugins/sonatype/build.gradle.kts b/plugins/sonatype/build.gradle.kts index bb33cf90..12114f94 100644 --- a/plugins/sonatype/build.gradle.kts +++ b/plugins/sonatype/build.gradle.kts @@ -36,4 +36,5 @@ kotlin { dependencies { implementation(libs.mavenPublishPlugin) + implementation(libs.kotlin.gradle.plugin) } diff --git a/plugins/sonatype/src/main/kotlin/com/powersync/plugins/utils/KmpUtils.kt b/plugins/sonatype/src/main/kotlin/com/powersync/plugins/utils/KmpUtils.kt new file mode 100644 index 00000000..c4fc0e83 --- /dev/null +++ b/plugins/sonatype/src/main/kotlin/com/powersync/plugins/utils/KmpUtils.kt @@ -0,0 +1,42 @@ +package com.powersync.plugins.utils + +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithPresetFunctions + +public fun KotlinTargetContainerWithPresetFunctions.powersyncTargets( + native: Boolean = true, + jvm: Boolean = true, + includeTargetsWithoutComposeSupport: Boolean = true, +) { + if (jvm) { + androidTarget { + publishLibraryVariants("release", "debug") + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } + + jvm { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) + // https://jakewharton.com/kotlins-jdk-release-compatibility-flag/ + freeCompilerArgs.add("-Xjdk-release=8") + } + } + } + + if (native) { + iosX64() + iosArm64() + iosSimulatorArm64() + + if (includeTargetsWithoutComposeSupport) { + macosX64() + macosArm64() + } + } +} diff --git a/static-sqlite-driver/build.gradle.kts b/static-sqlite-driver/build.gradle.kts index 2027bc1a..4a5b81c8 100644 --- a/static-sqlite-driver/build.gradle.kts +++ b/static-sqlite-driver/build.gradle.kts @@ -1,6 +1,7 @@ import java.io.File import java.io.FileInputStream import com.powersync.plugins.sonatype.setupGithubRepository +import com.powersync.plugins.utils.powersyncTargets import de.undercouch.gradle.tasks.download.Download import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader @@ -75,6 +76,8 @@ fun compileSqlite(target: KotlinNativeTarget): TaskProvider { KonanTarget.IOS_X64 -> "x86_64-apple-ios12.0-simulator" to "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk" KonanTarget.IOS_ARM64 -> "arm64-apple-ios12.0" to "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk" KonanTarget.IOS_SIMULATOR_ARM64 -> "arm64-apple-ios14.0-simulator" to "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk" + KonanTarget.MACOS_ARM64 -> "aarch64-apple-macos" to "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/" + KonanTarget.MACOS_X64 -> "x86_64-apple-macos" to "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/" else -> error("Unexpected target $target") } @@ -149,9 +152,8 @@ fun compileSqlite(target: KotlinNativeTarget): TaskProvider { } kotlin { - iosX64() - iosArm64() - iosSimulatorArm64() + // We use sqlite3-jdbc on JVM platforms instead + powersyncTargets(jvm=false) applyDefaultHierarchyTemplate() explicitApi()