-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for zulu like jdks by performing the java home check ba…
…sed on bin(executables folder). (#336) * Added support for zulu-like jdks by performing the java home check based on bin(executables folder). * Went back to the original approach with passing DoctorExtension directly into the JavaHomeCheck instead of using JavaHomeCheckConfigurations. Minor fix for extra message appending mechanism in case it's not set. --------- Co-authored-by: Nelson Osacky <nosacky@gradle.com>
- Loading branch information
1 parent
09c7c0a
commit 7442802
Showing
8 changed files
with
427 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 71 additions & 56 deletions
127
doctor-plugin/src/main/java/com/osacky/doctor/JavaHomeCheck.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,83 +1,98 @@ | ||
package com.osacky.doctor | ||
|
||
import com.gradle.develocity.agent.gradle.adapters.BuildScanAdapter | ||
import com.osacky.doctor.internal.DefaultPrescriptionGenerator | ||
import com.osacky.doctor.internal.JAVA_HOME_TAG | ||
import com.osacky.doctor.internal.JavaHomeCheckPrescriptionsGenerator | ||
import com.osacky.doctor.internal.PillBoxPrinter | ||
import org.gradle.api.GradleException | ||
import org.gradle.internal.jvm.Jvm | ||
import java.io.File | ||
import java.nio.file.NoSuchFileException | ||
import java.nio.file.Path | ||
import java.util.Collections | ||
import kotlin.collections.LinkedHashSet | ||
import kotlin.io.path.exists | ||
import kotlin.io.path.pathString | ||
|
||
internal const val JAVA_HOME = "JAVA_HOME" | ||
internal const val JAVA_EXECUTABLES_FOLDER = "bin" | ||
internal const val JAVA_HOME_NOT_FOUND = | ||
"There is no existing filesystem structure for %s. Please specify proper path for $JAVA_HOME!" | ||
|
||
class JavaHomeCheck( | ||
private val extension: DoctorExtension, | ||
jvmVariables: JvmVariables, | ||
private val javaHomeHandler: JavaHomeHandler, | ||
private val pillBoxPrinter: PillBoxPrinter, | ||
private val prescriptionsGenerator: JavaHomeCheckPrescriptionsGenerator = | ||
DefaultPrescriptionGenerator { javaHomeHandler.extraMessage.orNull }, | ||
) : BuildStartFinishListener, HasBuildScanTag { | ||
private val environmentJavaHome: String? = System.getenv("JAVA_HOME") | ||
private val gradleJavaHome = Jvm.current().javaHome | ||
private val gradleJavaExecutablePath by lazy { resolveExecutableJavaPath(jvmVariables.gradleJavaHome) } | ||
private val environmentJavaExecutablePath by lazy { resolveEnvironmentJavaHome(jvmVariables.environmentJavaHome) } | ||
private val recordedErrors = Collections.synchronizedSet(LinkedHashSet<String>()) | ||
private val isGradleUsingJavaHome: Boolean | ||
get() = gradleJavaExecutablePath == environmentJavaExecutablePath | ||
|
||
override fun onStart() { | ||
val extraMessage = extension.javaHomeHandler.extraMessage.orNull | ||
val failOnError = extension.javaHomeHandler.failOnError.get() | ||
|
||
if (extension.javaHomeHandler.ensureJavaHomeIsSet.get() && environmentJavaHome == null) { | ||
val message = | ||
buildString { | ||
appendln("JAVA_HOME is not set.") | ||
appendln( | ||
"Please set JAVA_HOME so that switching between Android Studio and the terminal does not trigger a full rebuild.", | ||
) | ||
appendln("To set JAVA_HOME: (using bash)") | ||
appendln("echo \"export JAVA_HOME=${'$'}(/usr/libexec/java_home)\" >> ~/.bash_profile") | ||
appendln("or `~/.zshrc` if using zsh.") | ||
extraMessage?.let { | ||
appendln() | ||
appendln(extraMessage) | ||
} | ||
} | ||
if (failOnError) { | ||
throw GradleException(pillBoxPrinter.createPill(message)) | ||
} else { | ||
recordedErrors.add(message) | ||
} | ||
} | ||
if (extension.javaHomeHandler.ensureJavaHomeMatches.get() && !isGradleUsingJavaHome()) { | ||
val message = | ||
buildString { | ||
appendln("Gradle is not using JAVA_HOME.") | ||
appendln("JAVA_HOME is ${environmentJavaHome?.toFile()?.toPath()?.toAbsolutePath()}") | ||
appendln("Gradle is using ${gradleJavaHome.toPath().toAbsolutePath()}") | ||
appendln("This can slow down your build significantly when switching from Android Studio to the terminal.") | ||
appendln("To fix: Project Structure -> JDK Location.") | ||
appendln("Set this to your JAVA_HOME.") | ||
extraMessage?.let { | ||
appendln() | ||
appendln(extraMessage) | ||
} | ||
} | ||
if (failOnError) { | ||
throw GradleException(pillBoxPrinter.createPill(message)) | ||
} else { | ||
recordedErrors.add(message) | ||
} | ||
} | ||
ensureJavaHomeIsSet() | ||
ensureJavaHomeMatchesGradleHome() | ||
} | ||
|
||
override fun onFinish(): List<String> { | ||
return recordedErrors.toList() | ||
} | ||
|
||
private fun isGradleUsingJavaHome(): Boolean { | ||
// Follow symlinks when checking that java home matches. | ||
if (environmentJavaHome != null && gradleJavaHome.toPath().toRealPath() == File(environmentJavaHome).toPath().toRealPath()) { | ||
return true | ||
override fun addCustomValues(buildScanApi: BuildScanAdapter) { | ||
buildScanApi.tag(JAVA_HOME_TAG) | ||
} | ||
|
||
private fun ensureJavaHomeIsSet() { | ||
if (javaHomeHandler.ensureJavaHomeIsSet.get() && environmentJavaExecutablePath == null) { | ||
failOrRecordMessage(prescriptionsGenerator.generateJavaHomeIsNotSetMessage()) | ||
} | ||
return false | ||
} | ||
|
||
private fun String.toFile() = File(this) | ||
private fun ensureJavaHomeMatchesGradleHome() { | ||
if (javaHomeHandler.ensureJavaHomeMatches.get() && !isGradleUsingJavaHome) { | ||
failOrRecordMessage( | ||
prescriptionsGenerator.generateJavaHomeMismatchesGradleHome( | ||
environmentJavaExecutablePath?.pathString, | ||
gradleJavaExecutablePath.pathString, | ||
), | ||
) | ||
} | ||
} | ||
|
||
override fun addCustomValues(buildScanApi: BuildScanAdapter) { | ||
buildScanApi.tag(JAVA_HOME_TAG) | ||
private fun failOrRecordMessage(message: String) { | ||
if (javaHomeHandler.failOnError.get()) { | ||
throw GradleException(pillBoxPrinter.createPill(message)) | ||
} else { | ||
recordedErrors.add(message) | ||
} | ||
} | ||
|
||
private fun resolveEnvironmentJavaHome(location: String?) = | ||
location?.let { | ||
resolveExecutableJavaPath(it) { path -> | ||
if (!path.exists()) { | ||
throw GradleException(String.format(JAVA_HOME_NOT_FOUND, path)) | ||
} | ||
return@resolveExecutableJavaPath path | ||
} | ||
} | ||
|
||
private fun resolveExecutableJavaPath( | ||
location: String, | ||
fallback: (Path) -> Path = { it }, | ||
): Path { | ||
val path = File(location).toPath() | ||
return try { | ||
// Follow symlinks when checking that java home matches. | ||
path.resolve(JAVA_EXECUTABLES_FOLDER).toRealPath() | ||
} catch (exc: NoSuchFileException) { | ||
// fallback to initial path | ||
return fallback(path) | ||
} | ||
} | ||
} | ||
|
||
data class JvmVariables(val environmentJavaHome: String?, val gradleJavaHome: String) |
68 changes: 68 additions & 0 deletions
68
...or-plugin/src/main/java/com/osacky/doctor/internal/JavaHomeCheckPrescriptionsGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Copyright 2024 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.osacky.doctor.internal | ||
|
||
internal const val NO_JAVA_HOME = "JAVA_HOME is not set." | ||
internal const val JAVA_HOME_AT_LOCATION = "JAVA_HOME is %s" | ||
internal const val GRADLE_JAVA_HOME_AT_LOCATION = "Gradle is using %s" | ||
internal const val NO_JAVA_HOME_MESSAGE = """ | ||
$NO_JAVA_HOME | ||
Please set JAVA_HOME so that switching between Android Studio and the terminal does not trigger a full rebuild. | ||
To set JAVA_HOME: (using bash) | ||
echo "export JAVA_HOME=${'$'}(/usr/libexec/java_home)" >> ~/.bash_profile | ||
or `~/.zshrc` if using zsh. | ||
%s | ||
""" | ||
|
||
internal const val JAVA_HOME_DOESNT_MATCH_GRADLE_HOME = """ | ||
Gradle is not using JAVA_HOME. | ||
%s | ||
%s | ||
This can slow down your build significantly when switching from Android Studio to the terminal. | ||
To fix: Project Structure -> JDK Location. | ||
Set this to your JAVA_HOME. | ||
%s | ||
""" | ||
|
||
interface JavaHomeCheckPrescriptionsGenerator { | ||
fun generateJavaHomeIsNotSetMessage(): String | ||
|
||
fun generateJavaHomeMismatchesGradleHome( | ||
javaHomeLocation: String?, | ||
gradleJavaHomeLocation: String, | ||
): String | ||
} | ||
|
||
internal class DefaultPrescriptionGenerator(private val extraMessage: () -> String?) : | ||
JavaHomeCheckPrescriptionsGenerator { | ||
override fun generateJavaHomeIsNotSetMessage() = String.format(NO_JAVA_HOME_MESSAGE, extraMessage().orEmpty()).trimIndent() | ||
|
||
override fun generateJavaHomeMismatchesGradleHome( | ||
javaHomeLocation: String?, | ||
gradleJavaHomeLocation: String, | ||
): String { | ||
val javaHomeMessage = | ||
javaHomeLocation?.let { String.format(JAVA_HOME_AT_LOCATION, it) } ?: NO_JAVA_HOME | ||
val gradleJavaHomeMessage = String.format(GRADLE_JAVA_HOME_AT_LOCATION, gradleJavaHomeLocation) | ||
return String.format( | ||
JAVA_HOME_DOESNT_MATCH_GRADLE_HOME, | ||
javaHomeMessage, | ||
gradleJavaHomeMessage, | ||
extraMessage().orEmpty(), | ||
).trimIndent() | ||
} | ||
} |
Oops, something went wrong.