1
1
package org.javacs.kt
2
2
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
8
3
import java.io.Closeable
9
4
import java.io.File
10
5
import java.nio.file.FileSystems
11
6
import java.nio.file.Files
12
7
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
13
15
14
16
/* *
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.
17
19
*/
18
20
class CompilerClassPath (
19
21
private val config : CompilerConfiguration ,
20
22
private val scriptsConfig : ScriptsConfiguration ,
21
23
private val codegenConfig : CodegenConfiguration ,
22
- private val databaseService : DatabaseService
24
+ private val databaseService : DatabaseService ,
23
25
) : Closeable {
24
26
val workspaceRoots = mutableSetOf<Path >()
25
27
@@ -29,14 +31,15 @@ class CompilerClassPath(
29
31
val outputDirectory: File = Files .createTempDirectory(" klsBuildOutput" ).toFile()
30
32
val javaHome: String? = System .getProperty(" java.home" , null )
31
33
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
+ )
40
43
private set
41
44
42
45
private val async = AsyncExecutor ()
@@ -49,53 +52,91 @@ class CompilerClassPath(
49
52
private fun refresh (
50
53
updateClassPath : Boolean = true,
51
54
updateBuildScriptClassPath : Boolean = true,
52
- updateJavaSourcePath : Boolean = true
55
+ updateJavaSourcePath : Boolean = true,
53
56
): Boolean {
54
- // TODO: Fetch class path and build script class path concurrently (and asynchronously)
55
57
val resolver = defaultClassPathResolver(workspaceRoots, databaseService.db)
56
58
var refreshCompiler = updateJavaSourcePath
57
59
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
59
100
val newClassPath = resolver.classpathOrEmpty
60
101
if (newClassPath != classPath) {
61
102
synchronized(classPath) {
62
103
syncPaths(classPath, newClassPath, " class path" ) { it.compiledJar }
63
104
}
64
- refreshCompiler = true
105
+ updated = true
65
106
}
66
107
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
71
112
}
72
113
}
114
+
115
+ updated
73
116
}
117
+ }
74
118
75
- if (updateBuildScriptClassPath) {
119
+ private fun updateBuildScriptClassPathAsync (
120
+ resolver : ClassPathResolver
121
+ ): CompletableFuture <Boolean > {
122
+ return async.compute {
123
+ var updated = false
76
124
LOG .info(" Update build script path" )
77
125
val newBuildScriptClassPath = resolver.buildScriptClasspathOrEmpty
78
126
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
81
137
}
138
+ updated
82
139
}
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
99
140
}
100
141
101
142
/* * Synchronizes the given two path sets and logs the differences. */
@@ -150,15 +191,22 @@ class CompilerClassPath(
150
191
val buildScript = isBuildScript(file)
151
192
val javaSource = isJavaSource(file)
152
193
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
+ )
154
199
} else {
155
200
return false
156
201
}
157
202
}
158
203
159
204
private fun isJavaSource (file : Path ): Boolean = file.fileName.toString().endsWith(" .java" )
160
205
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
+ }
162
210
163
211
private fun findJavaSourceFiles (root : Path ): Set <Path > {
164
212
val sourceMatcher = FileSystems .getDefault().getPathMatcher(" glob:*.java" )
0 commit comments