summaryrefslogtreecommitdiff
path: root/clientserver
diff options
context:
space:
mode:
authorRobby <robby@santoslab.org>2018-03-16 05:09:36 -0500
committerGitHub <noreply@github.com>2018-03-16 05:09:36 -0500
commit712f331d24d0934cd9c653a12be7e47e1fff1f5d (patch)
tree655df4d38c06ce8af2fc7acbfa4ef4b6c47be059 /clientserver
parent6c0276eb0846158c3a08ba3d05419f690c28376d (diff)
downloadmill-712f331d24d0934cd9c653a12be7e47e1fff1f5d.tar.gz
mill-712f331d24d0934cd9c653a12be7e47e1fff1f5d.tar.bz2
mill-712f331d24d0934cd9c653a12be7e47e1fff1f5d.zip
Windows non-interactive (client/server) support, and fix assembly and posix file permission (#228)
* Added support for non-interactive (client/server) mode on Windows * Fixed assembly URI path * Skip setting posix file permission on Windows
Diffstat (limited to 'clientserver')
-rw-r--r--clientserver/src/mill/clientserver/Client.java32
-rw-r--r--clientserver/src/mill/clientserver/ClientServer.java8
-rw-r--r--clientserver/src/mill/clientserver/Server.scala33
3 files changed, 58 insertions, 15 deletions
diff --git a/clientserver/src/mill/clientserver/Client.java b/clientserver/src/mill/clientserver/Client.java
index ed2fe6ad..248d3de1 100644
--- a/clientserver/src/mill/clientserver/Client.java
+++ b/clientserver/src/mill/clientserver/Client.java
@@ -1,9 +1,11 @@
package mill.clientserver;
import io.github.retronym.java9rtexport.Export;
-import org.scalasbt.ipcsocket.UnixDomainSocket;
+import org.scalasbt.ipcsocket.*;
import java.io.*;
+import java.net.Socket;
+import java.net.URISyntaxException;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
@@ -13,14 +15,15 @@ import java.util.Iterator;
import java.util.Properties;
public class Client {
- static void initServer(String lockBase) throws IOException{
+
+ static void initServer(String lockBase) throws IOException,URISyntaxException{
ArrayList<String> selfJars = new ArrayList<String>();
ClassLoader current = Client.class.getClassLoader();
while(current != null){
if (current instanceof java.net.URLClassLoader) {
URL[] urls = ((java.net.URLClassLoader) current).getURLs();
for (URL url: urls) {
- selfJars.add(url.toString());
+ selfJars.add(new File(url.toURI()).getCanonicalPath());
}
}
current = current.getParent();
@@ -71,7 +74,7 @@ public class Client {
public void run() {
try{
initServer(lockBase);
- }catch(IOException e){
+ }catch(Exception e){
throw new RuntimeException(e);
}
}
@@ -100,16 +103,26 @@ public class Client {
FileOutputStream f = new FileOutputStream(lockBase + "/run");
ClientServer.writeArgs(System.console() != null, args, f);
f.close();
- if (locks.processLock.probe()) initServer.run();
+
+ boolean serverInit = false;
+ if (locks.processLock.probe()) {
+ serverInit = true;
+ initServer.run();
+ }
while(locks.processLock.probe()) Thread.sleep(3);
+ // Need to give sometime for Win32NamedPipeSocket to work
+ // if the server is just initialized
+ if (serverInit && ClientServer.isWindows) Thread.sleep(250);
- UnixDomainSocket ioSocket = null;
+ Socket ioSocket = null;
long retryStart = System.currentTimeMillis();
while(ioSocket == null && System.currentTimeMillis() - retryStart < 1000){
try{
- ioSocket = new UnixDomainSocket(lockBase + "/io");
+ ioSocket = ClientServer.isWindows?
+ new Win32NamedPipeSocket(ClientServer.WIN32_PIPE_PREFIX + new File(lockBase).getName())
+ : new UnixDomainSocket(lockBase + "/io");
}catch(Throwable e){
Thread.sleep(1);
}
@@ -187,7 +200,10 @@ class ClientOutputPumper implements Runnable{
}
}
}catch(IOException e){
- throw new RuntimeException(e);
+ // Win32NamedPipeSocket input stream somehow doesn't return -1,
+ // but throw IOException whose message contains "ReadFile()" with a ccode
+ if (ClientServer.isWindows && e.getMessage().contains("ReadFile()")) running = false;
+ else throw new RuntimeException(e);
}
}
diff --git a/clientserver/src/mill/clientserver/ClientServer.java b/clientserver/src/mill/clientserver/ClientServer.java
index a8692c61..7af5845b 100644
--- a/clientserver/src/mill/clientserver/ClientServer.java
+++ b/clientserver/src/mill/clientserver/ClientServer.java
@@ -6,6 +6,14 @@ import java.io.InputStream;
import java.io.OutputStream;
class ClientServer {
+ public static boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
+
+ // Windows named pipe prefix (see https://github.com/sbt/ipcsocket/blob/v1.0.0/README.md)
+ // Win32NamedPipeServerSocket automatically adds this as a prefix (if it is not already is prefixed),
+ // but Win32NamedPipeSocket does not
+ // https://github.com/sbt/ipcsocket/blob/v1.0.0/src/main/java/org/scalasbt/ipcsocket/Win32NamedPipeServerSocket.java#L36
+ public static String WIN32_PIPE_PREFIX = "\\\\.\\pipe\\";
+
public static String[] parseArgs(InputStream argStream) throws IOException {
int argsLength = argStream.read();
diff --git a/clientserver/src/mill/clientserver/Server.scala b/clientserver/src/mill/clientserver/Server.scala
index 27c43302..dde727df 100644
--- a/clientserver/src/mill/clientserver/Server.scala
+++ b/clientserver/src/mill/clientserver/Server.scala
@@ -3,7 +3,7 @@ package mill.clientserver
import java.io._
import java.net.Socket
-import org.scalasbt.ipcsocket.{UnixDomainServerSocket, UnixDomainSocket}
+import org.scalasbt.ipcsocket._
trait ServerMain[T]{
def main(args0: Array[String]): Unit = {
@@ -37,18 +37,28 @@ class Server[T](lockBase: String,
var running = true
while (running) {
Server.lockBlock(locks.serverLock){
- new File(lockBase + "/io").delete()
- val ioSocket = new UnixDomainServerSocket(lockBase + "/io")
+ val (serverSocket, socketClose) = if (ClientServer.isWindows) {
+ val socketName = ClientServer.WIN32_PIPE_PREFIX + new File(lockBase).getName
+ (new Win32NamedPipeServerSocket(socketName), () => new Win32NamedPipeSocket(socketName).close())
+ } else {
+ val socketName = lockBase + "/io"
+ new File(socketName).delete()
+ (new UnixDomainServerSocket(socketName), () => new UnixDomainSocket(socketName).close())
+ }
+
val sockOpt = Server.interruptWith(
acceptTimeout,
- new UnixDomainSocket(lockBase + "/io").close(),
- ioSocket.accept()
+ socketClose(),
+ serverSocket.accept()
)
sockOpt match{
case None => running = false
case Some(sock) =>
- try handleRun(sock)
+ try {
+ handleRun(sock)
+ serverSocket.close()
+ }
catch{case e: Throwable => e.printStackTrace(originalStdout) }
}
}
@@ -106,7 +116,16 @@ class Server[T](lockBase: String,
t.interrupt()
t.stop()
- clientSocket.close()
+
+ if (ClientServer.isWindows) {
+ // Closing Win32NamedPipeSocket can often take ~5s
+ // It seems OK to exit the client early and subsequently
+ // start up mill client again (perhaps closing the server
+ // socket helps speed up the process).
+ val t = new Thread(() => clientSocket.close())
+ t.setDaemon(true)
+ t.start()
+ } else clientSocket.close()
}
}
object Server{