Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option to use runtimeClasspath in GradleClassPathResolver #590

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,44 @@ import java.nio.file.Path
import java.nio.file.PathMatcher
import java.nio.file.FileSystems

fun defaultClassPathResolver(workspaceRoots: Collection<Path>, db: Database? = null): ClassPathResolver {
data class ResolverOptions(
// Whether to use the compile classpath or the runtime classpath during classpath resolution
val useCompileClasspath: Boolean,
) {
companion object {
fun default(): ResolverOptions {
return ResolverOptions(useCompileClasspath = true)
}
}
}

val DefaultResolverOptions = ResolverOptions.default()

fun defaultClassPathResolver(
workspaceRoots: Collection<Path>,
db: Database? = null,
resolverOptions: ResolverOptions = DefaultResolverOptions,
): ClassPathResolver {
val childResolver = WithStdlibResolver(
ShellClassPathResolver.global(workspaceRoots.firstOrNull())
.or(workspaceRoots.asSequence().flatMap { workspaceResolvers(it) }.joined)
.or(workspaceRoots.asSequence().flatMap { workspaceResolvers(it, resolverOptions) }.joined)
).or(BackupClassPathResolver)

return db?.let { CachedClassPathResolver(childResolver, it) } ?: childResolver
}

/** Searches the workspace for all files that could provide classpath info. */
private fun workspaceResolvers(workspaceRoot: Path): Sequence<ClassPathResolver> {
private fun workspaceResolvers(workspaceRoot: Path, resolverOptions: ResolverOptions): Sequence<ClassPathResolver> {
val ignored: List<PathMatcher> = ignoredPathPatterns(workspaceRoot, workspaceRoot.resolve(".gitignore"))
return folderResolvers(workspaceRoot, ignored).asSequence()
return folderResolvers(workspaceRoot, ignored, resolverOptions).asSequence()
}

/** Searches the folder for all build-files. */
private fun folderResolvers(root: Path, ignored: List<PathMatcher>): Collection<ClassPathResolver> =
private fun folderResolvers(root: Path, ignored: List<PathMatcher>, resolverOptions: ResolverOptions): Collection<ClassPathResolver> =
root.toFile()
.walk()
.onEnter { file -> ignored.none { it.matches(file.toPath()) } }
.mapNotNull { asClassPathProvider(it.toPath()) }
.mapNotNull { asClassPathProvider(it.toPath(), resolverOptions) }
.toList()

/** Tries to read glob patterns from a gitignore. */
Expand All @@ -51,7 +68,7 @@ private fun ignoredPathPatterns(root: Path, gitignore: Path): List<PathMatcher>
?: emptyList()

/** Tries to create a classpath resolver from a file using as many sources as possible */
private fun asClassPathProvider(path: Path): ClassPathResolver? =
private fun asClassPathProvider(path: Path, resolverOptions: ResolverOptions): ClassPathResolver? =
MavenClassPathResolver.maybeCreate(path)
?: GradleClassPathResolver.maybeCreate(path)
?: GradleClassPathResolver.maybeCreate(path, resolverOptions)
?: ShellClassPathResolver.maybeCreate(path)
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@ import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

internal class GradleClassPathResolver(private val path: Path, private val includeKotlinDSL: Boolean): ClassPathResolver {
internal class GradleClassPathResolver(
private val path: Path,
private val includeKotlinDSL: Boolean,
private val useCompileClasspath: Boolean
): ClassPathResolver {
override val resolverType: String = "Gradle"
private val projectDirectory: Path get() = path.parent

override val classpath: Set<ClassPathEntry> get() {
val scripts = listOf("projectClassPathFinder.gradle")
val tasks = listOf("kotlinLSPProjectDeps")

return readDependenciesViaGradleCLI(projectDirectory, scripts, tasks)
return readDependenciesViaGradleCLI(projectDirectory, scripts, tasks, useCompileClasspath)
.apply { if (isNotEmpty()) LOG.info("Successfully resolved dependencies for '${projectDirectory.fileName}' using Gradle") }
.map { ClassPathEntry(it, null) }.toSet()
}
Expand All @@ -38,9 +42,15 @@ internal class GradleClassPathResolver(private val path: Path, private val inclu

companion object {
/** Create a Gradle resolver if a file is a pom. */
fun maybeCreate(file: Path): GradleClassPathResolver? =
fun maybeCreate(file: Path, options: ResolverOptions): GradleClassPathResolver? =
file.takeIf { file.endsWith("build.gradle") || file.endsWith("build.gradle.kts") }
?.let { GradleClassPathResolver(it, includeKotlinDSL = file.toString().endsWith(".kts")) }
?.let {
GradleClassPathResolver(
path = it,
includeKotlinDSL = file.endsWith(".kts"),
useCompileClasspath = options.useCompileClasspath,
)
}
}
}

Expand Down Expand Up @@ -73,13 +83,26 @@ private fun getGradleCommand(workspace: Path): Path {
}
}

private fun readDependenciesViaGradleCLI(projectDirectory: Path, gradleScripts: List<String>, gradleTasks: List<String>): Set<Path> {
private fun readDependenciesViaGradleCLI(
projectDirectory: Path,
gradleScripts: List<String>,
gradleTasks: List<String>,
useCompileClasspath: Boolean = true,
): Set<Path> {
LOG.info("Resolving dependencies for '{}' through Gradle's CLI using tasks {}...", projectDirectory.fileName, gradleTasks)

val tmpScripts = gradleScripts.map { gradleScriptToTempFile(it, deleteOnExit = false).toPath().toAbsolutePath() }
val gradle = getGradleCommand(projectDirectory)

val command = listOf(gradle.toString()) + tmpScripts.flatMap { listOf("-I", it.toString()) } + gradleTasks + listOf("--console=plain")
val command = mutableListOf<String>().apply {
add(gradle.toString())
addAll(tmpScripts.flatMap { listOf("-I", it.toString()) })
addAll(gradleTasks)
add("--console=plain")

if (useCompileClasspath) add("-PuseCompileClasspath=1")
}.toList()

val dependencies = findGradleCLIDependencies(command, projectDirectory)
?.also { LOG.debug("Classpath for task {}", it) }
.orEmpty()
Expand Down
5 changes: 4 additions & 1 deletion shared/src/main/resources/projectClassPathFinder.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ allprojects { project ->
}
} else if (project.hasProperty('sourceSets')) {
// Print the list of all dependencies jar files.
def useCompileClasspath = project.hasProperty("useCompileClasspath")

sourceSets.forEach {
it.compileClasspath.forEach {
def classPathSource = useCompileClasspath ? it.compileClasspath : it.runtimeClasspath
classPathSource.forEach {
System.out.println "kotlin-lsp-gradle $it"
}
}
Expand Down
Loading