11package 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
83import java.io.Closeable
94import java.io.File
105import java.nio.file.FileSystems
116import java.nio.file.Files
127import 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 */
1820class 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