Skip to content

Commit a46d02c

Browse files
feat: resolve todo by fetching paths async
1 parent dc24041 commit a46d02c

File tree

1 file changed

+93
-45
lines changed

1 file changed

+93
-45
lines changed

server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
package org.javacs.kt
22

3-
import org.javacs.kt.classpath.ClassPathEntry
4-
import org.javacs.kt.classpath.defaultClassPathResolver
5-
import org.javacs.kt.compiler.Compiler
6-
import org.javacs.kt.database.DatabaseService
7-
import org.javacs.kt.util.AsyncExecutor
83
import java.io.Closeable
94
import java.io.File
105
import java.nio.file.FileSystems
116
import java.nio.file.Files
127
import java.nio.file.Path
8+
import java.util.concurrent.CompletableFuture
9+
import org.javacs.kt.classpath.ClassPathEntry
10+
import org.javacs.kt.classpath.ClassPathResolver
11+
import org.javacs.kt.classpath.defaultClassPathResolver
12+
import org.javacs.kt.compiler.Compiler
13+
import org.javacs.kt.database.DatabaseService
14+
import org.javacs.kt.util.AsyncExecutor
1315

1416
/**
15-
* Manages the class path (compiled JARs, etc), the Java source path
16-
* and the compiler. Note that Kotlin sources are stored in SourcePath.
17+
* Manages the class path (compiled JARs, etc), the Java source path and the compiler. Note that
18+
* Kotlin sources are stored in SourcePath.
1719
*/
1820
class CompilerClassPath(
1921
private val config: CompilerConfiguration,
2022
private val scriptsConfig: ScriptsConfiguration,
2123
private val codegenConfig: CodegenConfiguration,
22-
private val databaseService: DatabaseService
24+
private val databaseService: DatabaseService,
2325
) : Closeable {
2426
val workspaceRoots = mutableSetOf<Path>()
2527

@@ -29,14 +31,15 @@ class CompilerClassPath(
2931
val outputDirectory: File = Files.createTempDirectory("klsBuildOutput").toFile()
3032
val javaHome: String? = System.getProperty("java.home", null)
3133

32-
var compiler = Compiler(
33-
javaSourcePath,
34-
classPath.map { it.compiledJar }.toSet(),
35-
buildScriptClassPath,
36-
scriptsConfig,
37-
codegenConfig,
38-
outputDirectory
39-
)
34+
var compiler =
35+
Compiler(
36+
javaSourcePath,
37+
classPath.map { it.compiledJar }.toSet(),
38+
buildScriptClassPath,
39+
scriptsConfig,
40+
codegenConfig,
41+
outputDirectory,
42+
)
4043
private set
4144

4245
private val async = AsyncExecutor()
@@ -49,53 +52,91 @@ class CompilerClassPath(
4952
private fun refresh(
5053
updateClassPath: Boolean = true,
5154
updateBuildScriptClassPath: Boolean = true,
52-
updateJavaSourcePath: Boolean = true
55+
updateJavaSourcePath: Boolean = true,
5356
): Boolean {
54-
// TODO: Fetch class path and build script class path concurrently (and asynchronously)
5557
val resolver = defaultClassPathResolver(workspaceRoots, databaseService.db)
5658
var refreshCompiler = updateJavaSourcePath
5759

58-
if (updateClassPath) {
60+
val classPathFuture =
61+
if (updateClassPath) {
62+
updateClassPathAsync(resolver)
63+
} else {
64+
CompletableFuture.completedFuture(false)
65+
}
66+
67+
val buildScriptClassPathFuture =
68+
if (updateBuildScriptClassPath) {
69+
updateBuildScriptClassPathAsync(resolver)
70+
} else {
71+
CompletableFuture.completedFuture(false)
72+
}
73+
74+
CompletableFuture.allOf(classPathFuture, buildScriptClassPathFuture).join()
75+
76+
refreshCompiler =
77+
refreshCompiler || classPathFuture.get() || buildScriptClassPathFuture.get()
78+
79+
if (refreshCompiler) {
80+
LOG.info("Reinstantiating compiler")
81+
compiler.close()
82+
compiler =
83+
Compiler(
84+
javaSourcePath,
85+
classPath.map { it.compiledJar }.toSet(),
86+
buildScriptClassPath,
87+
scriptsConfig,
88+
codegenConfig,
89+
outputDirectory,
90+
)
91+
updateCompilerConfiguration()
92+
}
93+
94+
return refreshCompiler
95+
}
96+
97+
private fun updateClassPathAsync(resolver: ClassPathResolver): CompletableFuture<Boolean> {
98+
return async.compute {
99+
var updated = false
59100
val newClassPath = resolver.classpathOrEmpty
60101
if (newClassPath != classPath) {
61102
synchronized(classPath) {
62103
syncPaths(classPath, newClassPath, "class path") { it.compiledJar }
63104
}
64-
refreshCompiler = true
105+
updated = true
65106
}
66107

67-
async.compute {
68-
val newClassPathWithSources = resolver.classpathWithSources
69-
synchronized(classPath) {
70-
syncPaths(classPath, newClassPathWithSources, "class path with sources") { it.compiledJar }
108+
val newClassPathWithSources = resolver.classpathWithSources
109+
synchronized(classPath) {
110+
syncPaths(classPath, newClassPathWithSources, "class path with sources") {
111+
it.compiledJar
71112
}
72113
}
114+
115+
updated
73116
}
117+
}
74118

75-
if (updateBuildScriptClassPath) {
119+
private fun updateBuildScriptClassPathAsync(
120+
resolver: ClassPathResolver
121+
): CompletableFuture<Boolean> {
122+
return async.compute {
123+
var updated = false
76124
LOG.info("Update build script path")
77125
val newBuildScriptClassPath = resolver.buildScriptClasspathOrEmpty
78126
if (newBuildScriptClassPath != buildScriptClassPath) {
79-
syncPaths(buildScriptClassPath, newBuildScriptClassPath, "build script class path") { it }
80-
refreshCompiler = true
127+
synchronized(buildScriptClassPath) {
128+
syncPaths(
129+
buildScriptClassPath,
130+
newBuildScriptClassPath,
131+
"build script class path",
132+
) {
133+
it
134+
}
135+
}
136+
updated = true
81137
}
138+
updated
82139
}
83-
84-
if (refreshCompiler) {
85-
LOG.info("Reinstantiating compiler")
86-
compiler.close()
87-
compiler = Compiler(
88-
javaSourcePath,
89-
classPath.map { it.compiledJar }.toSet(),
90-
buildScriptClassPath,
91-
scriptsConfig,
92-
codegenConfig,
93-
outputDirectory
94-
)
95-
updateCompilerConfiguration()
96-
}
97-
98-
return refreshCompiler
99140
}
100141

101142
/** Synchronizes the given two path sets and logs the differences. */
@@ -150,15 +191,22 @@ class CompilerClassPath(
150191
val buildScript = isBuildScript(file)
151192
val javaSource = isJavaSource(file)
152193
if (buildScript || javaSource) {
153-
return refresh(updateClassPath = buildScript, updateBuildScriptClassPath = false, updateJavaSourcePath = javaSource)
194+
return refresh(
195+
updateClassPath = buildScript,
196+
updateBuildScriptClassPath = false,
197+
updateJavaSourcePath = javaSource,
198+
)
154199
} else {
155200
return false
156201
}
157202
}
158203

159204
private fun isJavaSource(file: Path): Boolean = file.fileName.toString().endsWith(".java")
160205

161-
private fun isBuildScript(file: Path): Boolean = file.fileName.toString().let { it == "pom.xml" || it == "build.gradle" || it == "build.gradle.kts" }
206+
private fun isBuildScript(file: Path): Boolean =
207+
file.fileName.toString().let {
208+
it == "pom.xml" || it == "build.gradle" || it == "build.gradle.kts"
209+
}
162210

163211
private fun findJavaSourceFiles(root: Path): Set<Path> {
164212
val sourceMatcher = FileSystems.getDefault().getPathMatcher("glob:*.java")

0 commit comments

Comments
 (0)