@@ -3,31 +3,37 @@ package scala.build.bloop
3
3
import ch .epfl .scala .bsp4j
4
4
import org .eclipse .lsp4j .jsonrpc
5
5
6
- import java .io .IOException
6
+ import java .io .{ File , IOException }
7
7
import java .net .{ConnectException , Socket }
8
- import java .nio .file .{Files , Path }
8
+ import java .nio .file .{Files , Path , Paths }
9
9
import java .util .concurrent .{Future => JFuture , ScheduledExecutorService , TimeoutException }
10
10
11
11
import scala .annotation .tailrec
12
12
import scala .build .bloop .bloop4j .BloopExtraBuildParams
13
+ import scala .build .blooprifle .BloopRifleConfig .{AtLeast , Strict }
14
+ import scala .build .blooprifle ._
13
15
import scala .build .blooprifle .internal .Constants
14
- import scala .build .blooprifle .{BloopRifle , BloopRifleConfig , BloopRifleLogger , BspConnection }
15
16
import scala .concurrent .Await
16
- import scala .concurrent .duration .{ Duration , FiniteDuration }
17
+ import scala .concurrent .duration ._
17
18
import scala .jdk .CollectionConverters ._
18
19
19
20
trait BloopServer {
20
21
def server : BuildServer
21
22
22
23
def shutdown (): Unit
24
+
25
+ def jvmVersion : String
26
+
27
+ def bloopVersion : String
23
28
}
24
29
25
30
object BloopServer {
26
-
27
31
private case class BloopServerImpl (
28
32
server : BuildServer ,
29
33
listeningFuture : JFuture [Void ],
30
- socket : Socket
34
+ socket : Socket ,
35
+ jvmVersion : String ,
36
+ bloopVersion : String
31
37
) extends BloopServer {
32
38
def shutdown (): Unit = {
33
39
// Close the jsonrpc thread listening to input messages
@@ -37,31 +43,77 @@ object BloopServer {
37
43
}
38
44
}
39
45
46
+ private case class ResolvedBloopParameters (
47
+ bloopVersion : BloopVersion ,
48
+ jvmRelease : Int ,
49
+ javaPath : String
50
+ )
51
+
52
+ private def resolveBloopInfo (
53
+ bloopInfo : BloopServerRuntimeInfo ,
54
+ config : BloopRifleConfig
55
+ ): ResolvedBloopParameters = {
56
+ val bloopV : BloopVersion = config.retainedBloopVersion match {
57
+ case AtLeast (version) =>
58
+ val ord = Ordering .fromLessThan[BloopVersion ](_ isOlderThan _)
59
+ Seq (bloopInfo.bloopVersion, version).max(ord)
60
+ case Strict (version) => version
61
+ }
62
+ val jvmV = List (bloopInfo.jvmVersion, config.minimumBloopJvm).max
63
+ val bloopInfoJava = Paths .get(bloopInfo.javaHome, " bin" , " java" ).toString()
64
+ val expectedJava = if (jvmV >= bloopInfo.jvmVersion) config.javaPath else bloopInfoJava
65
+ ResolvedBloopParameters (bloopV, jvmV, expectedJava)
66
+ }
67
+
40
68
private def ensureBloopRunning (
41
69
config : BloopRifleConfig ,
42
70
startServerChecksPool : ScheduledExecutorService ,
43
71
logger : BloopRifleLogger
44
- ): Unit = {
45
-
46
- val isBloopRunning = BloopRifle .check(config, logger, startServerChecksPool)
47
-
48
- logger.debug(
49
- if (isBloopRunning) s " Bloop is running on ${config.host}: ${config.port}"
50
- else s " No bloop daemon found on ${config.host}: ${config.port}"
51
- )
52
-
53
- if (! isBloopRunning) {
54
- logger.debug(" Starting bloop server" )
55
- val serverStartedFuture = BloopRifle .startServer(
72
+ ): BloopServerRuntimeInfo = {
73
+ val workdir = new File (" ." ).getCanonicalFile.toPath
74
+ def startBloop (bloopVersion : String , bloopJava : String ) = {
75
+ logger.info(s " Starting bloop $bloopVersion on $bloopJava" )
76
+ val fut = BloopRifle .startServer(
56
77
config,
57
78
startServerChecksPool,
58
- logger
79
+ logger,
80
+ bloopVersion,
81
+ bloopJava
59
82
)
60
-
61
- Await .result(serverStartedFuture, Duration .Inf )
62
- logger.debug(" Bloop server started" )
83
+ Await .result(fut, 30 .seconds)
84
+ }
85
+ def exitBloop () = BloopRifle .exit(config, workdir, logger)
86
+
87
+ val bloopInfo =
88
+ BloopRifle .getCurrentBloopVersion(config, logger, workdir, startServerChecksPool)
89
+ val isRunning = BloopRifle .check(config, logger, startServerChecksPool)
90
+ val ResolvedBloopParameters (expectedBloopVersion, expectedBloopJvmRelease, javaPath) =
91
+ bloopInfo match {
92
+ case Left (error) =>
93
+ error match {
94
+ case BloopNotRunning =>
95
+ case ParsingFailed (bloopAboutOutput) =>
96
+ logger.info(s " Failed to parse output of 'bloop about': \n $bloopAboutOutput" )
97
+ }
98
+ ResolvedBloopParameters (
99
+ config.retainedBloopVersion.version,
100
+ config.minimumBloopJvm,
101
+ config.javaPath
102
+ )
103
+ case Right (value) => resolveBloopInfo(value, config)
104
+ }
105
+ val bloopVersionIsOk = bloopInfo.exists(_.bloopVersion == expectedBloopVersion)
106
+ val bloopJvmIsOk = bloopInfo.exists(_.jvmVersion == expectedBloopJvmRelease)
107
+ val isOk = bloopVersionIsOk && bloopJvmIsOk
108
+
109
+ if (! isOk) {
110
+ logger.info(s " Bloop currently running: $bloopInfo" )
111
+ if (isRunning) exitBloop()
112
+ startBloop(expectedBloopVersion.raw, javaPath)
63
113
}
64
114
115
+ BloopRifle .getCurrentBloopVersion(config, logger, workdir, startServerChecksPool)
116
+ .getOrElse(throw new RuntimeException (" Fatal error, could not spawn Bloop" ))
65
117
}
66
118
67
119
private def connect (
@@ -99,9 +151,9 @@ object BloopServer {
99
151
logger : BloopRifleLogger ,
100
152
period : FiniteDuration ,
101
153
timeout : FiniteDuration
102
- ): (BspConnection , Socket ) = {
154
+ ): (BspConnection , Socket , BloopServerRuntimeInfo ) = {
103
155
104
- ensureBloopRunning(config, threads.startServerChecks, logger)
156
+ val bloopInfo = ensureBloopRunning(config, threads.startServerChecks, logger)
105
157
106
158
logger.debug(" Opening BSP connection with bloop" )
107
159
Files .createDirectories(workspace.resolve(" .scala/.bloop" ))
@@ -116,7 +168,7 @@ object BloopServer {
116
168
117
169
logger.debug(s " Connected to Bloop via BSP at ${conn.address}" )
118
170
119
- (conn, socket)
171
+ (conn, socket, bloopInfo )
120
172
}
121
173
122
174
def buildServer (
@@ -130,7 +182,8 @@ object BloopServer {
130
182
logger : BloopRifleLogger
131
183
): BloopServer = {
132
184
133
- val (conn, socket) = bsp(config, workspace, threads, logger, config.period, config.timeout)
185
+ val (conn, socket, bloopInfo) =
186
+ bsp(config, workspace, threads, logger, config.period, config.timeout)
134
187
135
188
logger.debug(s " Connected to Bloop via BSP at ${conn.address}" )
136
189
@@ -172,7 +225,7 @@ object BloopServer {
172
225
}
173
226
174
227
server.onBuildInitialized()
175
- BloopServerImpl (server, f, socket)
228
+ BloopServerImpl (server, f, socket, bloopInfo.jvmVersion.toString(), bloopInfo.bloopVersion.raw )
176
229
}
177
230
178
231
def withBuildServer [T ](
@@ -206,5 +259,4 @@ object BloopServer {
206
259
}
207
260
// format: on
208
261
}
209
-
210
262
}
0 commit comments