in hot-reload-devtools/src/main/kotlin/org/jetbrains/compose/devtools/gradle/GradleRecompiler.kt [48:150]
override suspend fun buildAndReload(context: RecompilerContext): ExitCode {
val orchestrationPort = context.orchestration.port.awaitOrThrow()
/* Check if there is another known Gradle Process running */
val gradlePidFile = HotReloadEnvironment.pidFile?.let { pidFile ->
pidFile.resolveSibling("${pidFile.nameWithoutExtension}.gradle.pid")
}
/*
If we can find another process under the previous pid file:
- warn the user if possible
- wait for the previous build to finish
*/
if (gradlePidFile != null && gradlePidFile.isRegularFile()) run kill@{
val previousPid = runDirectoryLockFile?.withLock {
gradlePidFile.toFile().readText().toLongOrNull()
} ?: return@kill
val previousProcessHandle = ProcessHandle.of(previousPid).getOrNull() ?: return@kill
context.logger.error("Previous Gradle process with pid '$previousPid' found; Waiting...")
previousProcessHandle.onExit().toFuture().await()
}
/*
Launch the build, creating a new process.
*/
val processBuilder = context.process {
/* Setup JAVA_HOME: Prefer the java home of the original Gradle compilation */
if (HotReloadEnvironment.gradleJavaHome == null) {
context.logger.warn("Missing '${HotReloadProperty.GradleJavaHome}' property. Using system java")
}
val javaHome = HotReloadEnvironment.gradleJavaHome
?: System.getProperty("java.home")?.let(::Path)?.takeIf { it.exists() }
if (javaHome != null) {
environment()["JAVA_HOME"] = javaHome.pathString
}
/* Setup gradle wrapper command */
val gradleScriptCommand = if (Os.currentOrNull() == Os.Windows) arrayOf("cmd", "/c", "gradlew.bat")
else arrayOf("./gradlew")
val gradleTaskPath = if (buildProject == ":") ":$buildTask"
else "$buildProject:$buildTask"
directory(buildRoot.toFile())
redirectErrorStream(true)
command(
listOfNotNull(
*gradleScriptCommand,
gradleTaskPath,
"--console=plain",
"-D${HotReloadProperty.IsHotReloadBuild.key}=true",
"-P${HotReloadProperty.IsHotReloadBuild.key}=true",
*subprocessSystemProperties(BuildTool, orchestrationPort).toTypedArray(),
"-D${HotReloadProperty.GradleJavaHome.key}=${HotReloadEnvironment.gradleJavaHome?.pathString}"
.takeIf { HotReloadEnvironment.gradleJavaHome != null },
/* Continuous mode arguments */
"-t".takeIf { HotReloadEnvironment.gradleBuildContinuous },
"--no-daemon".takeIf { !useGradleDaemon },
"--offline".takeIf { HotReloadEnvironment.gradleOfflineMode },
/* Performance arguments */
"--configuration-cache".takeIf { HotReloadEnvironment.gradleBuildOptimize },
"--configuration-cache-problems=warn".takeIf { HotReloadEnvironment.gradleBuildOptimize },
"--build-cache".takeIf { HotReloadEnvironment.gradleBuildOptimize },
"--parallel".takeIf { HotReloadEnvironment.gradleBuildOptimize },
"-Pkotlin.internal.incremental.enableUnsafeOptimizationsForMultiplatform=true"
.takeIf { HotReloadEnvironment.gradleBuildOptimize }
)
)
}
/* Start the process and wire up the disposal */
val process = processBuilder.start()
context.invokeOnDispose { process.toHandle().destroyGradleProcess() }
context.logger.debug("'Recompiler': Started (${process.pid()})")
/* Write the pid file with the new process id */
runDirectoryLockFile?.withLock {
gradlePidFile?.writeText(process.pid().toString())
}
process.onExit().whenComplete { _, _ -> gradlePidFile?.deleteIfExists() }
/* Read the output of the new process and forward it as log messages */
withContext(Dispatchers.IO) {
process.inputStream.bufferedReader().forEachLine { line ->
val level = when {
line.startsWith("e: ") -> Level.Error
line.startsWith("warning: ") -> Level.Warn
line.startsWith("w: ") -> Level.Warn
line.startsWith(">") -> Level.Debug
else -> Level.Info
}
context.logger.log(level, line)
}
}
return ExitCode(process.onExit().toFuture().awaitOrThrow().exitValue())
}