Skip to content

Commit 2c76412

Browse files
committed
Use eclipse gradle plugin to get classpath with sources
1 parent 4bdd672 commit 2c76412

File tree

3 files changed

+73
-11
lines changed

3 files changed

+73
-11
lines changed

shared/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ dependencies {
2929
// dependencies are constrained to versions defined
3030
// in /gradle/platform/build.gradle.kts
3131
implementation(platform("dev.fwcd.kotlin-language-server:platform"))
32-
3332
implementation(kotlin("stdlib"))
33+
implementation("org.simpleframework:simple-xml:2.7.1")
34+
3435
testImplementation("org.hamcrest:hamcrest-all")
3536
testImplementation("junit:junit")
3637
}

shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,43 @@ import java.io.File
99
import java.nio.file.Files
1010
import java.nio.file.Path
1111
import java.nio.file.Paths
12+
import org.simpleframework.xml.Attribute
13+
import org.simpleframework.xml.ElementList
14+
import org.simpleframework.xml.Root
15+
import org.simpleframework.xml.Serializer
16+
import org.simpleframework.xml.core.Persister
17+
import kotlin.io.path.notExists
18+
import kotlin.io.path.readText
19+
20+
21+
@Root(strict = false)
22+
class XmlClasspathEntry {
23+
@field:Attribute(name = "kind", required = true)
24+
lateinit var kind: String
25+
26+
@field:Attribute(name = "path", required = false)
27+
var path: String? = null
28+
29+
@field:Attribute(name = "sourcepath", required = false)
30+
var sourcepath: String? = null
31+
}
32+
33+
@Root(strict = false, name = "classpath")
34+
class XmlClasspath {
35+
@field:ElementList(required = false, entry = "classpathentry", inline = true)
36+
lateinit var entries: List<XmlClasspathEntry>
37+
}
1238

1339
internal class GradleClassPathResolver(private val path: Path, private val includeKotlinDSL: Boolean): ClassPathResolver {
1440
override val resolverType: String = "Gradle"
1541
private val projectDirectory: Path get() = path.getParent()
1642
override val classpath: Set<ClassPathEntry> get() {
17-
val scripts = listOf("projectClassPathFinder.gradle")
18-
val tasks = listOf("kotlinLSPProjectDeps")
43+
val scripts = listOf("projectEclipseClassPathFinder.gradle")
44+
val tasks = listOf("eclipseClasspath")
45+
46+
executeGradleScript(projectDirectory, scripts, tasks)
1947

20-
return readDependenciesViaGradleCLI(projectDirectory, scripts, tasks)
21-
.apply { if (isNotEmpty()) LOG.info("Successfully resolved dependencies for '${projectDirectory.fileName}' using Gradle") }
22-
.map { ClassPathEntry(it, null) }.toSet()
48+
return parseDotClasspath(projectDirectory)
2349
}
2450
override val buildScriptClasspath: Set<Path> get() {
2551
return if (includeKotlinDSL) {
@@ -70,25 +96,33 @@ private fun getGradleCommand(workspace: Path): Path {
7096
}
7197
}
7298

73-
private fun readDependenciesViaGradleCLI(projectDirectory: Path, gradleScripts: List<String>, gradleTasks: List<String>): Set<Path> {
99+
private fun executeGradleScript(projectDirectory: Path, gradleScripts: List<String>, gradleTasks: List<String>): Pair<String, String> {
74100
LOG.info("Resolving dependencies for '{}' through Gradle's CLI using tasks {}...", projectDirectory.fileName, gradleTasks)
75101

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

79105
val command = listOf(gradle.toString()) + tmpScripts.flatMap { listOf("-I", it.toString()) } + gradleTasks + listOf("--console=plain")
80-
val dependencies = findGradleCLIDependencies(command, projectDirectory)
106+
LOG.debug("Running command: $command")
107+
val ret = execAndReadStdoutAndStderr(command, projectDirectory)
108+
tmpScripts.forEach(Files::delete)
109+
return ret
110+
}
111+
112+
private fun readDependenciesViaGradleCLI(projectDirectory: Path, gradleScripts: List<String>, gradleTasks: List<String>): Set<Path> {
113+
val (result, errors) = executeGradleScript(projectDirectory, gradleScripts, gradleTasks)
114+
115+
val dependencies = findGradleCLIDependencies(result, errors)
81116
?.also { LOG.debug("Classpath for task {}", it) }
82117
.orEmpty()
83118
.filter { it.toString().lowercase().endsWith(".jar") || Files.isDirectory(it) } // Some Gradle plugins seem to cause this to output POMs, therefore filter JARs
84119
.toSet()
85120

86-
tmpScripts.forEach(Files::delete)
121+
87122
return dependencies
88123
}
89124

90-
private fun findGradleCLIDependencies(command: List<String>, projectDirectory: Path): Set<Path>? {
91-
val (result, errors) = execAndReadStdoutAndStderr(command, projectDirectory)
125+
private fun findGradleCLIDependencies(result: String, errors: String): Set<Path>? {
92126
if ("FAILURE: Build failed" in errors) {
93127
LOG.warn("Gradle task failed: {}", errors)
94128
} else {
@@ -111,3 +145,27 @@ private fun parseGradleCLIDependencies(output: String): Set<Path>? {
111145
.filterNotNull()
112146
return artifacts.toSet()
113147
}
148+
149+
private fun parseDotClasspath(projectDirectory: Path) : Set<ClassPathEntry> {
150+
val dotClasspath = projectDirectory.resolve(".classpath")
151+
if (dotClasspath.notExists()){
152+
return emptySet()
153+
}
154+
val xmlToParse = dotClasspath.readText()
155+
val serializer: Serializer = Persister()
156+
val classpath = serializer.read(XmlClasspath::class.java, xmlToParse)
157+
val ret =
158+
classpath
159+
.entries
160+
.map {
161+
ClassPathEntry(Path.of(it.path ?: ""), Path.of(it.sourcepath ?: ""))
162+
}
163+
.toSet()
164+
165+
if (ret.isNotEmpty()) {
166+
LOG.info("Using classpath from .classpath")
167+
}
168+
dotClasspath.toFile().delete()
169+
return ret
170+
171+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
allprojects {
2+
apply plugin: "eclipse"
3+
}

0 commit comments

Comments
 (0)