Skip to content

Commit

Permalink
Add toolchains support to Gradle plugin (#5269)
Browse files Browse the repository at this point in the history
* Add jdkHome parameter to CLI

* Add toolchain support to Gradle plugin

This aligns to the behaviour of toolchains in the Kotlin Gradle Plugin.
KGP will set jvmTarget and jdkHome based on the enabled toolchain,
assuming it hasn't been set elsewhere in the build script.

* Fix lint error in test sources
  • Loading branch information
3flex committed Sep 10, 2022
1 parent c6ac2b5 commit c626f1e
Show file tree
Hide file tree
Showing 13 changed files with 87 additions and 5 deletions.
Expand Up @@ -193,6 +193,13 @@ class CliArgs {
)
var jvmTarget: String = JvmTarget.DEFAULT.description

@Parameter(
names = ["--jdk-home"],
description = "EXPERIMENTAL: Use a custom JDK home directory to include into the classpath",
converter = PathConverter::class
)
var jdkHome: Path? = null

@Parameter(
names = ["--version"],
description = "Prints the detekt CLI version."
Expand Down
Expand Up @@ -68,6 +68,7 @@ internal fun CliArgs.createSpec(output: Appendable, error: Appendable): Processi
jvmTarget = args.jvmTarget
languageVersion = args.languageVersion?.versionString
classpath = args.classpath?.trim()
jdkHome = args.jdkHome
}
}
}
Expand Down
Expand Up @@ -33,7 +33,8 @@ internal class EnvironmentFacade(
projectSpec.inputPaths.toList(),
classpath,
compilerSpec.parseLanguageVersion(),
compilerSpec.parseJvmTarget()
compilerSpec.parseJvmTarget(),
compilerSpec.jdkHome,
)
createKotlinCoreEnvironment(compilerConfiguration, disposable)
}
Expand Down
2 changes: 2 additions & 0 deletions detekt-gradle-plugin/settings.gradle.kts
Expand Up @@ -2,6 +2,8 @@ pluginManagement {
includeBuild("../build-logic")
}

includeBuild("..")

dependencyResolutionManagement {
versionCatalogs {
create("libs") {
Expand Down
Expand Up @@ -19,13 +19,15 @@ import io.gitlab.arturbosch.detekt.invoke.DetektInvoker
import io.gitlab.arturbosch.detekt.invoke.DisableDefaultRuleSetArgument
import io.gitlab.arturbosch.detekt.invoke.FailFastArgument
import io.gitlab.arturbosch.detekt.invoke.InputArgument
import io.gitlab.arturbosch.detekt.invoke.JdkHomeArgument
import io.gitlab.arturbosch.detekt.invoke.JvmTargetArgument
import io.gitlab.arturbosch.detekt.invoke.LanguageVersionArgument
import io.gitlab.arturbosch.detekt.invoke.ParallelArgument
import io.gitlab.arturbosch.detekt.invoke.isDryRunEnabled
import org.gradle.api.Action
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileTree
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
Expand All @@ -38,6 +40,7 @@ import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Console
import org.gradle.api.tasks.IgnoreEmptyDirectories
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
Expand Down Expand Up @@ -96,6 +99,11 @@ abstract class Detekt @Inject constructor(
get() = jvmTargetProp.get()
set(value) = jvmTargetProp.set(value)

@get:InputDirectory
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:Optional
abstract val jdkHome: DirectoryProperty

@get:Internal
internal abstract val debugProp: Property<Boolean>
var debug: Boolean
Expand Down Expand Up @@ -216,6 +224,7 @@ abstract class Detekt @Inject constructor(
ClasspathArgument(classpath),
LanguageVersionArgument(languageVersionProp.orNull),
JvmTargetArgument(jvmTargetProp.orNull),
JdkHomeArgument(jdkHome),
ConfigArgument(config),
BaselineArgument(baseline.orNull),
DefaultReportArgument(DetektReportType.XML, xmlReportFile.orNull),
Expand Down
Expand Up @@ -17,6 +17,7 @@ import io.gitlab.arturbosch.detekt.invoke.InputArgument
import io.gitlab.arturbosch.detekt.invoke.JvmTargetArgument
import io.gitlab.arturbosch.detekt.invoke.ParallelArgument
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileTree
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
Expand All @@ -26,6 +27,7 @@ import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Console
import org.gradle.api.tasks.IgnoreEmptyDirectories
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Optional
Expand Down Expand Up @@ -113,6 +115,11 @@ abstract class DetektCreateBaselineTask : SourceTask() {
get() = jvmTargetProp.get()
set(value) = jvmTargetProp.set(value)

@get:InputDirectory
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:Optional
abstract val jdkHome: DirectoryProperty

@get:Internal
internal val arguments: Provider<List<String>> = project.provider {
listOf(
Expand Down
Expand Up @@ -3,8 +3,12 @@ package io.gitlab.arturbosch.detekt.internal
import io.gitlab.arturbosch.detekt.Detekt
import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.toolchain.JavaToolchainService

internal fun Project.registerDetektTask(
name: String,
Expand Down Expand Up @@ -40,6 +44,20 @@ internal fun Project.registerDetektTask(
}
}

project.plugins.withType(JavaBasePlugin::class.java) { _ ->
val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain

// acquire a provider that returns the launcher for the toolchain
val service = project.extensions.getByType(JavaToolchainService::class.java)
val defaultLauncher = service.launcherFor(toolchain)
it.jdkHome.convention(defaultLauncher.map { launcher -> launcher.metadata.installationPath })
it.jvmTargetProp.convention(
defaultLauncher.map { launcher ->
JavaVersion.toVersion(launcher.metadata.languageVersion.asInt()).toString()
}
)
}

it.debugProp.convention(provider { extension.debug })
it.parallelProp.convention(provider { extension.parallel })
it.disableDefaultRuleSetsProp.convention(provider { extension.disableDefaultRuleSets })
Expand All @@ -59,6 +77,20 @@ internal fun Project.registerCreateBaselineTask(
configuration: DetektCreateBaselineTask.() -> Unit
): TaskProvider<DetektCreateBaselineTask> =
tasks.register(name, DetektCreateBaselineTask::class.java) {
project.plugins.withType(JavaBasePlugin::class.java) { _ ->
val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain

// acquire a provider that returns the launcher for the toolchain
val service = project.extensions.getByType(JavaToolchainService::class.java)
val defaultLauncher = service.launcherFor(toolchain)
it.jdkHome.convention(defaultLauncher.map { launcher -> launcher.metadata.installationPath })
it.jvmTargetProp.convention(
defaultLauncher.map { launcher ->
JavaVersion.toVersion(launcher.metadata.languageVersion.asInt()).toString()
}
)
}

it.config.setFrom(project.provider { extension.config })
it.debug.convention(project.provider { extension.debug })
it.parallel.convention(project.provider { extension.parallel })
Expand Down
@@ -1,6 +1,7 @@
package io.gitlab.arturbosch.detekt.invoke

import io.gitlab.arturbosch.detekt.extensions.DetektReportType
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection
import org.gradle.api.file.RegularFile
import java.io.File
Expand All @@ -21,6 +22,7 @@ private const val CREATE_BASELINE_PARAMETER = "--create-baseline"
private const val CLASSPATH_PARAMETER = "--classpath"
private const val LANGUAGE_VERSION_PARAMETER = "--language-version"
private const val JVM_TARGET_PARAMETER = "--jvm-target"
private const val JDK_HOME_PARAMETER = "--jdk-home"
private const val BASE_PATH_PARAMETER = "--base-path"

internal sealed class CliArgument {
Expand Down Expand Up @@ -58,6 +60,10 @@ internal data class JvmTargetArgument(val jvmTarget: String?) : CliArgument() {
override fun toArgument() = jvmTarget?.let { listOf(JVM_TARGET_PARAMETER, it) }.orEmpty()
}

internal data class JdkHomeArgument(val jdkHome: DirectoryProperty) : CliArgument() {
override fun toArgument() = jdkHome.orNull?.let { listOf(JDK_HOME_PARAMETER, it.toString()) }.orEmpty()
}

internal data class BaselineArgument(val baseline: RegularFile?) : CliArgument() {
override fun toArgument() = baseline?.let { listOf(BASELINE_PARAMETER, it.asFile.absolutePath) }.orEmpty()
}
Expand Down
@@ -1,5 +1,5 @@
@file:JvmName("Main")
@file:Suppress("unused", "UNUSED_PARAMETER")
@file:Suppress("unused", "UNUSED_PARAMETER", "Filename")

package io.gitlab.arturbosch.detekt.cli

Expand Down
Expand Up @@ -67,7 +67,8 @@ fun createCompilerConfiguration(
pathsToAnalyze: List<Path>,
classpath: List<String>,
languageVersion: LanguageVersion?,
jvmTarget: JvmTarget
jvmTarget: JvmTarget,
jdkHome: Path?,
): CompilerConfiguration {
val javaFiles = pathsToAnalyze.flatMap { path ->
path.toFile().walk()
Expand Down Expand Up @@ -99,6 +100,8 @@ fun createCompilerConfiguration(
addJavaSourceRoots(javaFiles)
addKotlinSourceRoots(kotlinFiles)
addJvmClasspathRoots(classpathFiles)

jdkHome?.let { put(JVMConfigurationKeys.JDK_HOME, it.toFile()) }
configureJdkClasspathRoots()
}
}
Expand Down
3 changes: 3 additions & 0 deletions detekt-tooling/api/detekt-tooling.api
Expand Up @@ -116,6 +116,7 @@ public abstract interface class io/github/detekt/tooling/api/spec/BaselineSpec {

public abstract interface class io/github/detekt/tooling/api/spec/CompilerSpec {
public abstract fun getClasspath ()Ljava/lang/String;
public abstract fun getJdkHome ()Ljava/nio/file/Path;
public abstract fun getJvmTarget ()Ljava/lang/String;
public abstract fun getLanguageVersion ()Ljava/lang/String;
}
Expand Down Expand Up @@ -243,9 +244,11 @@ public final class io/github/detekt/tooling/dsl/CompilerSpecBuilder : io/github/
public fun build ()Lio/github/detekt/tooling/api/spec/CompilerSpec;
public synthetic fun build ()Ljava/lang/Object;
public final fun getClasspath ()Ljava/lang/String;
public final fun getJdkHome ()Ljava/nio/file/Path;
public final fun getJvmTarget ()Ljava/lang/String;
public final fun getLanguageVersion ()Ljava/lang/String;
public final fun setClasspath (Ljava/lang/String;)V
public final fun setJdkHome (Ljava/nio/file/Path;)V
public final fun setJvmTarget (Ljava/lang/String;)V
public final fun setLanguageVersion (Ljava/lang/String;)V
}
Expand Down
@@ -1,5 +1,7 @@
package io.github.detekt.tooling.api.spec

import java.nio.file.Path

/**
* All these properties are based down to the Kotlin compiler for type- and symbol resolution.
*/
Expand All @@ -19,4 +21,10 @@ interface CompilerSpec {
* Paths to class files and jars separated by a path separator.
*/
val classpath: String?

/**
* Path to custom JDK home. Includes the custom JDK from the specified location into the classpath instead of using
* the JRE from the runtime environment.
*/
val jdkHome: Path?
}
@@ -1,19 +1,22 @@
package io.github.detekt.tooling.dsl

import io.github.detekt.tooling.api.spec.CompilerSpec
import java.nio.file.Path

@ProcessingModelDsl
class CompilerSpecBuilder : Builder<CompilerSpec> {

var jvmTarget: String = "1.8"
var languageVersion: String? = null
var classpath: String? = null
var jdkHome: Path? = null

override fun build(): CompilerSpec = CompilerModel(jvmTarget, languageVersion, classpath)
override fun build(): CompilerSpec = CompilerModel(jvmTarget, languageVersion, classpath, jdkHome)
}

private data class CompilerModel(
override val jvmTarget: String,
override val languageVersion: String?,
override val classpath: String?
override val classpath: String?,
override val jdkHome: Path?,
) : CompilerSpec

0 comments on commit c626f1e

Please sign in to comment.