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
13
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
14
15
15
16
/* *
16
- * Manages the class path (compiled JARs, etc), the Java source path
17
- * 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.
18
19
*/
19
20
class CompilerClassPath (
20
21
private val config : CompilerConfiguration ,
21
22
private val scriptsConfig : ScriptsConfiguration ,
22
23
private val codegenConfig : CodegenConfiguration ,
23
- private val databaseService : DatabaseService
24
+ private val databaseService : DatabaseService ,
24
25
) : Closeable {
25
26
val workspaceRoots = mutableSetOf<Path >()
26
27
@@ -30,14 +31,15 @@ class CompilerClassPath(
30
31
val outputDirectory: File = Files .createTempDirectory(" klsBuildOutput" ).toFile()
31
32
val javaHome: String? = System .getProperty(" java.home" , null )
32
33
33
- var compiler = Compiler (
34
- javaSourcePath,
35
- classPath.map { it.compiledJar }.toSet(),
36
- buildScriptClassPath,
37
- scriptsConfig,
38
- codegenConfig,
39
- outputDirectory
40
- )
34
+ var compiler =
35
+ Compiler (
36
+ javaSourcePath,
37
+ classPath.map { it.compiledJar }.toSet(),
38
+ buildScriptClassPath,
39
+ scriptsConfig,
40
+ codegenConfig,
41
+ outputDirectory,
42
+ )
41
43
private set
42
44
43
45
private val async = AsyncExecutor ()
@@ -50,65 +52,94 @@ class CompilerClassPath(
50
52
private fun refresh (
51
53
updateClassPath : Boolean = true,
52
54
updateBuildScriptClassPath : Boolean = true,
53
- updateJavaSourcePath : Boolean = true
55
+ updateJavaSourcePath : Boolean = true,
54
56
): Boolean {
55
57
val resolver = defaultClassPathResolver(workspaceRoots, databaseService.db)
56
58
var refreshCompiler = updateJavaSourcePath
57
- val asyncExecutor = AsyncExecutor ()
58
-
59
- val classPathFuture = if (updateClassPath) {
60
- asyncExecutor.compute {
61
- val newClassPath = resolver.classpathOrEmpty
62
- if (newClassPath != classPath) {
63
- synchronized(classPath) {
64
- syncPaths(classPath, newClassPath, " class path" ) { it.compiledJar }
65
- }
66
- refreshCompiler = true
67
- }
68
59
69
- asyncExecutor.compute {
70
- val newClassPathWithSources = resolver.classpathWithSources
71
- synchronized(classPath) {
72
- syncPaths(classPath, newClassPathWithSources, " class path with sources" ) { it.compiledJar }
73
- }
74
- }
60
+ val classPathFuture =
61
+ if (updateClassPath) {
62
+ updateClassPathAsync(resolver)
63
+ } else {
64
+ CompletableFuture .completedFuture(false )
75
65
}
76
- } else {
77
- CompletableFuture .completedFuture(null )
78
- }
79
66
80
- val buildScriptClassPathFuture = if (updateBuildScriptClassPath) {
81
- asyncExecutor.compute {
82
- LOG .info(" Update build script path" )
83
- val newBuildScriptClassPath = resolver.buildScriptClasspathOrEmpty
84
- if (newBuildScriptClassPath != buildScriptClassPath) {
85
- syncPaths(buildScriptClassPath, newBuildScriptClassPath, " build script class path" ) { it }
86
- refreshCompiler = true
87
- }
67
+ val buildScriptClassPathFuture =
68
+ if (updateBuildScriptClassPath) {
69
+ updateBuildScriptClassPathAsync(resolver)
70
+ } else {
71
+ CompletableFuture .completedFuture(false )
88
72
}
89
- } else {
90
- CompletableFuture .completedFuture(null )
91
- }
92
73
74
+ // Wait for both futures to complete
93
75
CompletableFuture .allOf(classPathFuture, buildScriptClassPathFuture).join()
94
76
77
+ // Update refreshCompiler based on the results of the futures
78
+ refreshCompiler =
79
+ refreshCompiler || classPathFuture.get() || buildScriptClassPathFuture.get()
80
+
95
81
if (refreshCompiler) {
96
82
LOG .info(" Reinstantiating compiler" )
97
83
compiler.close()
98
- compiler = Compiler (
99
- javaSourcePath,
100
- classPath.map { it.compiledJar }.toSet(),
101
- buildScriptClassPath,
102
- scriptsConfig,
103
- codegenConfig,
104
- outputDirectory
105
- )
84
+ compiler =
85
+ Compiler (
86
+ javaSourcePath,
87
+ classPath.map { it.compiledJar }.toSet(),
88
+ buildScriptClassPath,
89
+ scriptsConfig,
90
+ codegenConfig,
91
+ outputDirectory,
92
+ )
106
93
updateCompilerConfiguration()
107
94
}
108
95
109
96
return refreshCompiler
110
97
}
111
98
99
+ private fun updateClassPathAsync (resolver : ClassPathResolver ): CompletableFuture <Boolean > {
100
+ return async.compute {
101
+ var updated = false
102
+ val newClassPath = resolver.classpathOrEmpty
103
+ if (newClassPath != classPath) {
104
+ synchronized(classPath) {
105
+ syncPaths(classPath, newClassPath, " class path" ) { it.compiledJar }
106
+ }
107
+ updated = true
108
+ }
109
+
110
+ val newClassPathWithSources = resolver.classpathWithSources
111
+ synchronized(classPath) {
112
+ syncPaths(classPath, newClassPathWithSources, " class path with sources" ) {
113
+ it.compiledJar
114
+ }
115
+ }
116
+
117
+ updated
118
+ }
119
+ }
120
+
121
+ private fun updateBuildScriptClassPathAsync (
122
+ resolver : ClassPathResolver
123
+ ): CompletableFuture <Boolean > {
124
+ return async.compute {
125
+ var updated = false
126
+ LOG .info(" Update build script path" )
127
+ val newBuildScriptClassPath = resolver.buildScriptClasspathOrEmpty
128
+ if (newBuildScriptClassPath != buildScriptClassPath) {
129
+ synchronized(buildScriptClassPath) {
130
+ syncPaths(
131
+ buildScriptClassPath,
132
+ newBuildScriptClassPath,
133
+ " build script class path" ,
134
+ ) {
135
+ it
136
+ }
137
+ }
138
+ updated = true
139
+ }
140
+ updated
141
+ }
142
+ }
112
143
113
144
/* * Synchronizes the given two path sets and logs the differences. */
114
145
private fun <T > syncPaths (dest : MutableSet <T >, new : Set <T >, name : String , toPath : (T ) -> Path ) {
@@ -162,15 +193,22 @@ class CompilerClassPath(
162
193
val buildScript = isBuildScript(file)
163
194
val javaSource = isJavaSource(file)
164
195
if (buildScript || javaSource) {
165
- return refresh(updateClassPath = buildScript, updateBuildScriptClassPath = false , updateJavaSourcePath = javaSource)
196
+ return refresh(
197
+ updateClassPath = buildScript,
198
+ updateBuildScriptClassPath = false ,
199
+ updateJavaSourcePath = javaSource,
200
+ )
166
201
} else {
167
202
return false
168
203
}
169
204
}
170
205
171
206
private fun isJavaSource (file : Path ): Boolean = file.fileName.toString().endsWith(" .java" )
172
207
173
- private fun isBuildScript (file : Path ): Boolean = file.fileName.toString().let { it == " pom.xml" || it == " build.gradle" || it == " build.gradle.kts" }
208
+ private fun isBuildScript (file : Path ): Boolean =
209
+ file.fileName.toString().let {
210
+ it == " pom.xml" || it == " build.gradle" || it == " build.gradle.kts"
211
+ }
174
212
175
213
private fun findJavaSourceFiles (root : Path ): Set <Path > {
176
214
val sourceMatcher = FileSystems .getDefault().getPathMatcher(" glob:*.java" )
0 commit comments