summaryrefslogtreecommitdiff
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
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
-rwxr-xr-xbuild.sc12
-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
-rw-r--r--main/src/mill/modules/Jvm.scala26
-rw-r--r--main/test/src/mill/eval/JavaCompileJarTests.scala2
6 files changed, 81 insertions, 32 deletions
diff --git a/build.sc b/build.sc
index 847296cb..c012c77b 100755
--- a/build.sc
+++ b/build.sc
@@ -236,11 +236,13 @@ object dev extends MillModule{
write(outputPath, prependShellScript())
- val perms = java.nio.file.Files.getPosixFilePermissions(outputPath.toNIO)
- perms.add(PosixFilePermission.GROUP_EXECUTE)
- perms.add(PosixFilePermission.OWNER_EXECUTE)
- perms.add(PosixFilePermission.OTHERS_EXECUTE)
- java.nio.file.Files.setPosixFilePermissions(outputPath.toNIO, perms)
+ if (!scala.util.Properties.isWin) {
+ val perms = java.nio.file.Files.getPosixFilePermissions(outputPath.toNIO)
+ perms.add(PosixFilePermission.GROUP_EXECUTE)
+ perms.add(PosixFilePermission.OWNER_EXECUTE)
+ perms.add(PosixFilePermission.OTHERS_EXECUTE)
+ java.nio.file.Files.setPosixFilePermissions(outputPath.toNIO, perms)
+ }
PathRef(outputPath)
}
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{
diff --git a/main/src/mill/modules/Jvm.scala b/main/src/mill/modules/Jvm.scala
index dba3552d..291d4151 100644
--- a/main/src/mill/modules/Jvm.scala
+++ b/main/src/mill/modules/Jvm.scala
@@ -241,7 +241,7 @@ object Jvm {
(implicit ctx: Ctx.Dest) = {
val tmp = ctx.dest / "out-tmp.jar"
- val baseUri = "jar:file:" + tmp
+ val baseUri = "jar:" + tmp.toIO.getCanonicalFile.toURI.toASCIIString
val hm = new java.util.HashMap[String, String]()
base match{
@@ -278,11 +278,13 @@ object Jvm {
IO.stream(read.getInputStream(tmp), outputStream)
outputStream.close()
- val perms = Files.getPosixFilePermissions(output.toNIO)
- perms.add(PosixFilePermission.GROUP_EXECUTE)
- perms.add(PosixFilePermission.OWNER_EXECUTE)
- perms.add(PosixFilePermission.OTHERS_EXECUTE)
- Files.setPosixFilePermissions(output.toNIO, perms)
+ if (!scala.util.Properties.isWin) {
+ val perms = Files.getPosixFilePermissions(output.toNIO)
+ perms.add(PosixFilePermission.GROUP_EXECUTE)
+ perms.add(PosixFilePermission.OWNER_EXECUTE)
+ perms.add(PosixFilePermission.OTHERS_EXECUTE)
+ Files.setPosixFilePermissions(output.toNIO, perms)
+ }
}
PathRef(output)
@@ -328,11 +330,13 @@ object Jvm {
write(outputPath, launcherShellScript(mainClass, classPath.map(_.toString), jvmArgs))
- val perms = Files.getPosixFilePermissions(outputPath.toNIO)
- perms.add(PosixFilePermission.GROUP_EXECUTE)
- perms.add(PosixFilePermission.OWNER_EXECUTE)
- perms.add(PosixFilePermission.OTHERS_EXECUTE)
- Files.setPosixFilePermissions(outputPath.toNIO, perms)
+ if (!scala.util.Properties.isWin) {
+ val perms = Files.getPosixFilePermissions(outputPath.toNIO)
+ perms.add(PosixFilePermission.GROUP_EXECUTE)
+ perms.add(PosixFilePermission.OWNER_EXECUTE)
+ perms.add(PosixFilePermission.OTHERS_EXECUTE)
+ Files.setPosixFilePermissions(outputPath.toNIO, perms)
+ }
PathRef(outputPath)
}
diff --git a/main/test/src/mill/eval/JavaCompileJarTests.scala b/main/test/src/mill/eval/JavaCompileJarTests.scala
index 78cf09a5..1ac00c79 100644
--- a/main/test/src/mill/eval/JavaCompileJarTests.scala
+++ b/main/test/src/mill/eval/JavaCompileJarTests.scala
@@ -114,7 +114,7 @@ object JavaCompileJarTests extends TestSuite{
|test/FooTwo.class
|hello.txt
|""".stripMargin
- assert(jarContents == expectedJarContents)
+ assert(jarContents.lines.toSeq == expectedJarContents.lines.toSeq)
val executed = %%('java, "-cp", evaluator.outPath/'jar/'dest/"out.jar", "test.Foo")(evaluator.outPath).out.string
assert(executed == (31337 + 271828) + System.lineSeparator)