Skip to content

Commit ad4809e

Browse files
Rename main class
So that the server is easier to spot in the 'jps' output.
1 parent f99c580 commit ad4809e

File tree

4 files changed

+193
-184
lines changed

4 files changed

+193
-184
lines changed

bloopgun/src/main/scala/bloop/bloopgun/Bloopgun.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ class BloopgunCli(
552552
val cmd = javaBinary ++ finalJvmOpts(jvmOpts) ++ List(
553553
"-classpath",
554554
stringClasspath,
555-
"bloop.Server"
555+
"bloop.Server" // "bloop.Bloop" works too in recent versions (>= 1.4.13)
556556
) ++ serverArgs
557557
cmd -> usedExtraJvmOpts
558558
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package bloop
2+
3+
import java.net.InetAddress
4+
5+
import bloop.logging.BloopLogger
6+
import bloop.logging.Logger
7+
import bloop.util.ProxySetup
8+
9+
import java.io.InputStream
10+
import java.io.PrintStream
11+
import java.nio.channels.ReadableByteChannel
12+
import java.nio.file.Files
13+
import java.nio.file.Paths
14+
import java.util.concurrent.atomic.AtomicBoolean
15+
16+
import com.martiansoftware.nailgun.NGListeningAddress
17+
import com.martiansoftware.nailgun.NGConstants
18+
import com.martiansoftware.nailgun.{Alias, NGContext, NGServer}
19+
import libdaemonjvm._
20+
import libdaemonjvm.internal.{LockProcess, SocketHandler}
21+
import libdaemonjvm.server._
22+
23+
import scala.util.Properties
24+
import scala.util.Try
25+
import java.net.ServerSocket
26+
import java.net.Socket
27+
import java.io.OutputStream
28+
import java.net.SocketAddress
29+
import java.nio.channels.Channels
30+
import libdaemonjvm.internal.SocketMaker
31+
import java.nio.ByteBuffer
32+
import java.io.File
33+
import org.slf4j
34+
35+
sealed abstract class Bloop
36+
37+
object Bloop {
38+
private val defaultPort: Int = 8212 // 8100 + 'p'
39+
def main(args: Array[String]): Unit = {
40+
def toPortNumber(userPort: String) = Try(userPort.toInt).getOrElse(Bloop.defaultPort)
41+
val lockFilesOrHostPort = args match {
42+
case Array() =>
43+
val lockFiles = LockFiles.under(
44+
bloop.io.Paths.daemonDir.underlying,
45+
bloop.io.Paths.pipeName
46+
)
47+
Right(lockFiles)
48+
case Array(daemonArg) if daemonArg.startsWith("daemon:") =>
49+
val arg = daemonArg.stripPrefix("daemon:")
50+
val (dirStr, pipeName) = arg.split(File.pathSeparator, 2) match {
51+
case Array(dir, pipeName) => (dir, pipeName)
52+
case Array(dir) => (dir, bloop.io.Paths.pipeName)
53+
}
54+
val dir = Paths.get(dirStr)
55+
val lockFiles = LockFiles.under(dir, pipeName)
56+
Right(lockFiles)
57+
case Array(arg) =>
58+
Left((InetAddress.getLoopbackAddress(), toPortNumber(args(0))))
59+
case Array(host, portStr) =>
60+
val addr = InetAddress.getByName(host)
61+
Left((addr, toPortNumber(portStr)))
62+
case _ =>
63+
throw new IllegalArgumentException(
64+
s"Invalid arguments to bloop server: $args, expected: ([address] [port] | [daemon:path] [pipeName])"
65+
)
66+
}
67+
68+
lockFilesOrHostPort match {
69+
case Left(hostPort) =>
70+
startServer(Left(hostPort))
71+
case Right(lockFiles) =>
72+
Lock.tryAcquire(lockFiles, LockProcess.default) {
73+
startServer(Right(lockFiles.socketPaths))
74+
} match {
75+
case Left(err) => throw new Exception(err)
76+
case Right(()) =>
77+
}
78+
}
79+
}
80+
81+
def startServer(socketPathsOrHostPort: Either[(InetAddress, Int), SocketPaths]): Unit = {
82+
val socketAndPathOrHostPort = socketPathsOrHostPort.map { socketPaths =>
83+
val socket = SocketHandler.server(socketPaths) match {
84+
case Left(socket) => socket
85+
case Right(channel) => libdaemonjvm.Util.serverSocketFromChannel(channel)
86+
}
87+
val (socketPathStr, socketPathOpt) =
88+
if (SocketHandler.usesWindowsPipe) (socketPaths.windowsPipeName, None)
89+
else (socketPaths.path.toString, Some(socketPaths.path))
90+
(socket, socketPathStr, socketPathOpt)
91+
}
92+
val server = instantiateServer(socketAndPathOrHostPort.map {
93+
case (sock, path, _) => (sock, path)
94+
})
95+
val runServer: Runnable = () =>
96+
try server.run()
97+
finally {
98+
for (path <- socketAndPathOrHostPort.toOption.flatMap(_._3))
99+
Files.deleteIfExists(path)
100+
}
101+
// FIXME Small delay between the time this method returns, and the time we actually
102+
// accept connections on the socket. This might make concurrent attempts to start a server
103+
// think we are a zombie server, and attempt to listen on the socket too.
104+
new Thread(runServer, "bloop-server").start()
105+
}
106+
107+
private[bloop] def instantiateServer(
108+
socketAndPathOrHostPort: Either[(InetAddress, Int), (ServerSocket, String)]
109+
): NGServer = {
110+
val logger = BloopLogger.default("bloop-nailgun-main")
111+
socketAndPathOrHostPort match {
112+
case Left((addr, port)) =>
113+
val tcpAddress = new NGListeningAddress(addr, port)
114+
launchServer(System.in, System.out, System.err, tcpAddress, logger, None)
115+
case Right((socket, socketPath)) =>
116+
val socketAddress = new NGListeningAddress(socketPath)
117+
launchServer(System.in, System.out, System.err, socketAddress, logger, Some(socket))
118+
}
119+
}
120+
121+
private[bloop] def launchServer(
122+
in: InputStream,
123+
out: PrintStream,
124+
err: PrintStream,
125+
address: NGListeningAddress,
126+
logger: Logger,
127+
serverSocketOpt: Option[ServerSocket]
128+
): NGServer = {
129+
val javaLogger = slf4j.LoggerFactory.getLogger(classOf[NGServer])
130+
val poolSize = NGServer.DEFAULT_SESSIONPOOLSIZE
131+
val heartbeatMs = NGConstants.HEARTBEAT_TIMEOUT_MILLIS.toInt
132+
133+
val domainSocketProvider: NGServer.DomainSocketProvider = { () =>
134+
serverSocketOpt.getOrElse(
135+
sys.error("Shouldn't be called")
136+
)
137+
}
138+
139+
val server =
140+
new NGServer(address, poolSize, heartbeatMs, in, out, err, javaLogger, domainSocketProvider)
141+
registerAliases(server)
142+
ProxySetup.init()
143+
server
144+
}
145+
146+
def nailMain(ngContext: NGContext): Unit = {
147+
val server = ngContext.getNGServer
148+
149+
val soft = ngContext.getArgs.contains("--soft")
150+
151+
// Passing true by default to force exiting the JVM (System.exit).
152+
// When using JNI/JNA-based domain sockets, it seems the call to accept()
153+
// isn't interrupted when the underlying socket is closed (on Linux at least).
154+
// So we have to force a call to System.exit to actually exit.
155+
server.shutdown(!soft)
156+
}
157+
158+
private def registerAliases(server: NGServer): Unit = {
159+
val aliasManager = server.getAliasManager
160+
aliasManager.addAlias(new Alias("about", "Show bloop information.", classOf[Cli]))
161+
aliasManager.addAlias(new Alias("clean", "Clean project(s) in the build.", classOf[Cli]))
162+
aliasManager.addAlias(new Alias("compile", "Compile project(s) in the build.", classOf[Cli]))
163+
aliasManager.addAlias(new Alias("test", "Run project(s)' tests in the build.", classOf[Cli]))
164+
aliasManager.addAlias(
165+
new Alias("run", "Run a main entrypoint for project(s) in the build.", classOf[Cli])
166+
)
167+
aliasManager.addAlias(new Alias("bsp", "Spawn a build server protocol instance.", classOf[Cli]))
168+
aliasManager.addAlias(
169+
new Alias("console", "Run the console for project(s) in the build.", classOf[Cli])
170+
)
171+
aliasManager.addAlias(new Alias("projects", "Show projects in the build.", classOf[Cli]))
172+
aliasManager.addAlias(new Alias("configure", "Configure the bloop server.", classOf[Cli]))
173+
aliasManager.addAlias(new Alias("help", "Show bloop help message.", classOf[Cli]))
174+
aliasManager.addAlias(
175+
new Alias(
176+
"exit",
177+
"Kill the bloop server.",
178+
classOf[Bloop]
179+
)
180+
)
181+
182+
// Register the default entrypoint in case the user doesn't use the right alias
183+
server.setDefaultNailClass(classOf[Cli])
184+
// Disable nails by class name so that we prevent classloading incorrect aliases
185+
server.setAllowNailsByClassName(false)
186+
}
187+
}
Lines changed: 3 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,186 +1,8 @@
11
package bloop
22

3-
import java.net.InetAddress
3+
sealed abstract class Server
44

5-
import bloop.logging.BloopLogger
6-
import bloop.logging.Logger
7-
import bloop.util.ProxySetup
8-
9-
import java.io.InputStream
10-
import java.io.PrintStream
11-
import java.nio.channels.ReadableByteChannel
12-
import java.nio.file.Files
13-
import java.nio.file.Paths
14-
import java.util.concurrent.atomic.AtomicBoolean
15-
16-
import com.martiansoftware.nailgun.NGListeningAddress
17-
import com.martiansoftware.nailgun.NGConstants
18-
import com.martiansoftware.nailgun.{Alias, NGContext, NGServer}
19-
import libdaemonjvm._
20-
import libdaemonjvm.internal.{LockProcess, SocketHandler}
21-
import libdaemonjvm.server._
22-
23-
import scala.util.Properties
24-
import scala.util.Try
25-
import java.net.ServerSocket
26-
import java.net.Socket
27-
import java.io.OutputStream
28-
import java.net.SocketAddress
29-
import java.nio.channels.Channels
30-
import libdaemonjvm.internal.SocketMaker
31-
import java.nio.ByteBuffer
32-
import java.io.File
33-
import org.slf4j
34-
35-
class Server
365
object Server {
37-
private val defaultPort: Int = 8212 // 8100 + 'p'
38-
def main(args: Array[String]): Unit = {
39-
def toPortNumber(userPort: String) = Try(userPort.toInt).getOrElse(Server.defaultPort)
40-
val lockFilesOrHostPort = args match {
41-
case Array() =>
42-
val lockFiles = LockFiles.under(
43-
bloop.io.Paths.daemonDir.underlying,
44-
bloop.io.Paths.pipeName
45-
)
46-
Right(lockFiles)
47-
case Array(daemonArg) if daemonArg.startsWith("daemon:") =>
48-
val arg = daemonArg.stripPrefix("daemon:")
49-
val (dirStr, pipeName) = arg.split(File.pathSeparator, 2) match {
50-
case Array(dir, pipeName) => (dir, pipeName)
51-
case Array(dir) => (dir, bloop.io.Paths.pipeName)
52-
}
53-
val dir = Paths.get(dirStr)
54-
val lockFiles = LockFiles.under(dir, pipeName)
55-
Right(lockFiles)
56-
case Array(arg) =>
57-
Left((InetAddress.getLoopbackAddress(), toPortNumber(args(0))))
58-
case Array(host, portStr) =>
59-
val addr = InetAddress.getByName(host)
60-
Left((addr, toPortNumber(portStr)))
61-
case _ =>
62-
throw new IllegalArgumentException(
63-
s"Invalid arguments to bloop server: $args, expected: ([address] [port] | [daemon:path] [pipeName])"
64-
)
65-
}
66-
67-
lockFilesOrHostPort match {
68-
case Left(hostPort) =>
69-
startServer(Left(hostPort))
70-
case Right(lockFiles) =>
71-
Lock.tryAcquire(lockFiles, LockProcess.default) {
72-
startServer(Right(lockFiles.socketPaths))
73-
} match {
74-
case Left(err) => throw new Exception(err)
75-
case Right(()) =>
76-
}
77-
}
78-
}
79-
80-
def startServer(socketPathsOrHostPort: Either[(InetAddress, Int), SocketPaths]): Unit = {
81-
val socketAndPathOrHostPort = socketPathsOrHostPort.map { socketPaths =>
82-
val socket = SocketHandler.server(socketPaths) match {
83-
case Left(socket) => socket
84-
case Right(channel) => libdaemonjvm.Util.serverSocketFromChannel(channel)
85-
}
86-
val (socketPathStr, socketPathOpt) =
87-
if (SocketHandler.usesWindowsPipe) (socketPaths.windowsPipeName, None)
88-
else (socketPaths.path.toString, Some(socketPaths.path))
89-
(socket, socketPathStr, socketPathOpt)
90-
}
91-
val server = instantiateServer(socketAndPathOrHostPort.map {
92-
case (sock, path, _) => (sock, path)
93-
})
94-
val runServer: Runnable = () =>
95-
try server.run()
96-
finally {
97-
for (path <- socketAndPathOrHostPort.toOption.flatMap(_._3))
98-
Files.deleteIfExists(path)
99-
}
100-
// FIXME Small delay between the time this method returns, and the time we actually
101-
// accept connections on the socket. This might make concurrent attempts to start a server
102-
// think we are a zombie server, and attempt to listen on the socket too.
103-
new Thread(runServer, "bloop-server").start()
104-
}
105-
106-
private[bloop] def instantiateServer(
107-
socketAndPathOrHostPort: Either[(InetAddress, Int), (ServerSocket, String)]
108-
): NGServer = {
109-
val logger = BloopLogger.default("bloop-nailgun-main")
110-
socketAndPathOrHostPort match {
111-
case Left((addr, port)) =>
112-
val tcpAddress = new NGListeningAddress(addr, port)
113-
launchServer(System.in, System.out, System.err, tcpAddress, logger, None)
114-
case Right((socket, socketPath)) =>
115-
val socketAddress = new NGListeningAddress(socketPath)
116-
launchServer(System.in, System.out, System.err, socketAddress, logger, Some(socket))
117-
}
118-
}
119-
120-
private[bloop] def launchServer(
121-
in: InputStream,
122-
out: PrintStream,
123-
err: PrintStream,
124-
address: NGListeningAddress,
125-
logger: Logger,
126-
serverSocketOpt: Option[ServerSocket]
127-
): NGServer = {
128-
val javaLogger = slf4j.LoggerFactory.getLogger(classOf[NGServer])
129-
val poolSize = NGServer.DEFAULT_SESSIONPOOLSIZE
130-
val heartbeatMs = NGConstants.HEARTBEAT_TIMEOUT_MILLIS.toInt
131-
132-
val domainSocketProvider: NGServer.DomainSocketProvider = { () =>
133-
serverSocketOpt.getOrElse(
134-
sys.error("Shouldn't be called")
135-
)
136-
}
137-
138-
val server =
139-
new NGServer(address, poolSize, heartbeatMs, in, out, err, javaLogger, domainSocketProvider)
140-
registerAliases(server)
141-
ProxySetup.init()
142-
server
143-
}
144-
145-
def nailMain(ngContext: NGContext): Unit = {
146-
val server = ngContext.getNGServer
147-
148-
val soft = ngContext.getArgs.contains("--soft")
149-
150-
// Passing true by default to force exiting the JVM (System.exit).
151-
// When using JNI/JNA-based domain sockets, it seems the call to accept()
152-
// isn't interrupted when the underlying socket is closed (on Linux at least).
153-
// So we have to force a call to System.exit to actually exit.
154-
server.shutdown(!soft)
155-
}
156-
157-
private def registerAliases(server: NGServer): Unit = {
158-
val aliasManager = server.getAliasManager
159-
aliasManager.addAlias(new Alias("about", "Show bloop information.", classOf[Cli]))
160-
aliasManager.addAlias(new Alias("clean", "Clean project(s) in the build.", classOf[Cli]))
161-
aliasManager.addAlias(new Alias("compile", "Compile project(s) in the build.", classOf[Cli]))
162-
aliasManager.addAlias(new Alias("test", "Run project(s)' tests in the build.", classOf[Cli]))
163-
aliasManager.addAlias(
164-
new Alias("run", "Run a main entrypoint for project(s) in the build.", classOf[Cli])
165-
)
166-
aliasManager.addAlias(new Alias("bsp", "Spawn a build server protocol instance.", classOf[Cli]))
167-
aliasManager.addAlias(
168-
new Alias("console", "Run the console for project(s) in the build.", classOf[Cli])
169-
)
170-
aliasManager.addAlias(new Alias("projects", "Show projects in the build.", classOf[Cli]))
171-
aliasManager.addAlias(new Alias("configure", "Configure the bloop server.", classOf[Cli]))
172-
aliasManager.addAlias(new Alias("help", "Show bloop help message.", classOf[Cli]))
173-
aliasManager.addAlias(
174-
new Alias(
175-
"exit",
176-
"Kill the bloop server.",
177-
classOf[Server]
178-
)
179-
)
180-
181-
// Register the default entrypoint in case the user doesn't use the right alias
182-
server.setDefaultNailClass(classOf[Cli])
183-
// Disable nails by class name so that we prevent classloading incorrect aliases
184-
server.setAllowNailsByClassName(false)
185-
}
6+
def main(args: Array[String]): Unit =
7+
Bloop.main(args)
1868
}

0 commit comments

Comments
 (0)