diff options
author | Robby <robby@santoslab.org> | 2018-03-16 05:09:36 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-16 05:09:36 -0500 |
commit | 712f331d24d0934cd9c653a12be7e47e1fff1f5d (patch) | |
tree | 655df4d38c06ce8af2fc7acbfa4ef4b6c47be059 /clientserver/src | |
parent | 6c0276eb0846158c3a08ba3d05419f690c28376d (diff) | |
download | mill-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/src')
-rw-r--r-- | clientserver/src/mill/clientserver/Client.java | 32 | ||||
-rw-r--r-- | clientserver/src/mill/clientserver/ClientServer.java | 8 | ||||
-rw-r--r-- | clientserver/src/mill/clientserver/Server.scala | 33 |
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{ |