diff --git a/functionalTests/src/test/kotlin/org/jetbrains/compose/reload/utils/Transaction.kt b/functionalTests/src/test/kotlin/org/jetbrains/compose/reload/utils/Transaction.kt index d587e2a3..87f9f4e1 100644 --- a/functionalTests/src/test/kotlin/org/jetbrains/compose/reload/utils/Transaction.kt +++ b/functionalTests/src/test/kotlin/org/jetbrains/compose/reload/utils/Transaction.kt @@ -113,6 +113,12 @@ class TransactionScope( } } + suspend fun sync() { + val ping = OrchestrationMessage.Ping() + ping.send() + awaitAck(ping) + } + suspend fun awaitAck(message: OrchestrationMessage) { /* There is no ACK for an ACK, and there is also no ACk for a shutdown request. @@ -127,16 +133,20 @@ class TransactionScope( val reloadRequest = skipToMessage() val reloadResult = skipToMessage() if (!reloadResult.isSuccess) { - fail("Failed to reload classes: ${reloadResult.errorMessage}") + fail("Failed to reload classes: ${reloadResult.errorMessage}", Throwable(reloadResult.errorMessage).apply { + stackTrace = reloadResult.errorStacktrace?.toTypedArray().orEmpty() + }) } val rendered = skipToMessage() assertEquals(reloadRequest.messageId, rendered.reloadRequestId) + sync() } suspend infix fun initialSourceCode(source: String): Path { val file = writeCode(source = source) launchApplicationAndWait() + sync() return file } @@ -176,7 +186,3 @@ class TransactionScope( return resolvedFile } } - -fun awaitAck(message: OrchestrationMessage): suspend TransactionScope.() -> Unit = { - this.awaitAck(message) -} diff --git a/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reload.kt b/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reload.kt index 17383fb3..e0e975ab 100644 --- a/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reload.kt +++ b/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reload.kt @@ -69,7 +69,7 @@ internal fun reload( val daos = DataOutputStream(baos) clazz.classFile.write(daos) - ClassDefinition(Class.forName(clazz.name), baos.toByteArray()) + ClassDefinition(originalClass ?: Class.forName(clazz.name), baos.toByteArray()) } instrumentation.redefineClasses(*definitions.toTypedArray()) @@ -78,4 +78,3 @@ internal fun reload( definition.reinitializeStaticsIfNecessary() } } - diff --git a/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reloadClassesRequestHandler.kt b/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reloadClassesRequestHandler.kt index 4ce5496c..fa3d2c66 100644 --- a/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reloadClassesRequestHandler.kt +++ b/hot-reload-agent/src/main/kotlin/org/jetbrains/compose/reload/agent/reloadClassesRequestHandler.kt @@ -2,6 +2,7 @@ package org.jetbrains.compose.reload.agent import org.jetbrains.compose.reload.core.createLogger +import org.jetbrains.compose.reload.core.withLinearClosure import org.jetbrains.compose.reload.orchestration.OrchestrationMessage import org.jetbrains.compose.reload.orchestration.invokeWhenReceived import java.io.File @@ -35,7 +36,9 @@ internal fun launchReloadClassesRequestHandler(instrumentation: Instrumentation) if (result.isFailure) { logger.orchestration("Failed to reload classes", result.exceptionOrNull()) OrchestrationMessage.ReloadClassesResult( - request.messageId, false, result.exceptionOrNull()?.message + request.messageId, false, result.exceptionOrNull()?.message, + result.exceptionOrNull()?.withLinearClosure { throwable -> throwable.cause }.orEmpty() + .flatMap { throwable -> throwable.stackTrace.toList() } ).send() } diff --git a/hot-reload-gradle-plugin/src/main/kotlin/org/jetbrains/compose/reload/reloadClassesTask.kt b/hot-reload-gradle-plugin/src/main/kotlin/org/jetbrains/compose/reload/reloadClassesTask.kt index 7c30e710..66a7021f 100644 --- a/hot-reload-gradle-plugin/src/main/kotlin/org/jetbrains/compose/reload/reloadClassesTask.kt +++ b/hot-reload-gradle-plugin/src/main/kotlin/org/jetbrains/compose/reload/reloadClassesTask.kt @@ -3,6 +3,7 @@ package org.jetbrains.compose.reload import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.Directory import org.gradle.api.tasks.* import org.gradle.kotlin.dsl.property import org.gradle.kotlin.dsl.withType @@ -13,10 +14,14 @@ import org.jetbrains.compose.reload.orchestration.OrchestrationClientRole.Compil import org.jetbrains.compose.reload.orchestration.OrchestrationMessage import org.jetbrains.compose.reload.orchestration.OrchestrationMessage.ReloadClassesRequest import org.jetbrains.compose.reload.orchestration.OrchestrationMessage.ReloadClassesRequest.ChangeType +import org.jetbrains.compose.reload.orchestration.asBlockingQueue import org.jetbrains.compose.reload.orchestration.connectOrchestrationClient import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import java.io.File +import java.util.concurrent.TimeUnit import kotlin.system.exitProcess +import kotlin.time.Duration.Companion.nanoseconds +import kotlin.time.Duration.Companion.seconds internal fun Project.setupComposeReloadHotClasspathTasks() { @@ -36,12 +41,11 @@ internal fun Project.setupComposeReloadHotClasspathTasks() { internal fun Project.setupComposeReloadHotClasspathTask(compilation: KotlinCompilation<*>): TaskProvider { val name = composeReloadHotClasspathTaskName(compilation) if (name in tasks.names) return tasks.named(name, ComposeReloadHotClasspathTask::class.java) - val hotRuntimeClasses = compilation.hotRuntimeClasspath val hotApplicationClasses = compilation.hotApplicationClasspath return tasks.register(name, ComposeReloadHotClasspathTask::class.java) { task -> - task.classpath.from(hotRuntimeClasses) - task.finalizedBy(hotApplicationClasses) + task.classpath.from(hotApplicationClasses) + task.dependsOn(hotApplicationClasses) } } @@ -60,7 +64,7 @@ internal open class ComposeReloadHotClasspathTask : DefaultTask() { @get:Incremental val classpath: ConfigurableFileCollection = project.objects.fileCollection() - @Internal + @get:Internal val agentPort = project.objects.property() @TaskAction diff --git a/hot-reload-orchestration/src/main/kotlin/org/jetbrains/compose/reload/orchestration/OrchestrationMessage.kt b/hot-reload-orchestration/src/main/kotlin/org/jetbrains/compose/reload/orchestration/OrchestrationMessage.kt index 757b4f4c..6951720b 100644 --- a/hot-reload-orchestration/src/main/kotlin/org/jetbrains/compose/reload/orchestration/OrchestrationMessage.kt +++ b/hot-reload-orchestration/src/main/kotlin/org/jetbrains/compose/reload/orchestration/OrchestrationMessage.kt @@ -85,7 +85,8 @@ public sealed class OrchestrationMessage : Serializable { public data class ReloadClassesResult( val reloadRequestId: UUID, val isSuccess: Boolean, - val errorMessage: String? = null + val errorMessage: String? = null, + val errorStacktrace: List? = null, ) : OrchestrationMessage() /**