package mill.main.client; 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.util.*; public class MillClientMain { static void initServer(String lockBase, boolean setJnaNoSys) throws IOException,URISyntaxException{ String[] selfJars = System.getProperty("MILL_CLASSPATH").split(","); List l = new ArrayList<>(); List vmOptions = new ArrayList<>(); l.add("java"); final Properties props = System.getProperties(); for(final String k: props.stringPropertyNames()){ if (k.startsWith("MILL_") && !"MILL_CLASSPATH".equals(k)) { vmOptions.add("-D" + k + "=" + props.getProperty(k)); } } if (setJnaNoSys) { vmOptions.add("-Djna.nosys=true"); } if(!Util.isWindows){ l.addAll(vmOptions); } else { final File vmOptionsFile = new File(lockBase, "vmoptions"); try (PrintWriter out = new PrintWriter(vmOptionsFile)) { for(String opt: vmOptions) out.println(opt); } l.add("-XX:VMOptionsFile=" + vmOptionsFile.getCanonicalPath()); } l.add("-cp"); l.add(String.join(File.pathSeparator, selfJars)); l.add("mill.main.MillServerMain"); l.add(lockBase); new ProcessBuilder() .command(l) .redirectOutput(new java.io.File(lockBase + "/logs")) .redirectError(new java.io.File(lockBase + "/logs")) .start(); } public static void main(String[] args) throws Exception{ System.exit(main0(args)); } public static int main0(String[] args) throws Exception{ boolean setJnaNoSys = System.getProperty("jna.nosys") == null; Map env = System.getenv(); if (setJnaNoSys) { System.setProperty("jna.nosys", "true"); } int index = 0; while (index < 5) { index += 1; String lockBase = "out/mill-worker-" + index; new java.io.File(lockBase).mkdirs(); try(RandomAccessFile lockFile = new RandomAccessFile(lockBase + "/clientLock", "rw"); FileChannel channel = lockFile.getChannel(); java.nio.channels.FileLock tryLock = channel.tryLock(); Locks locks = Locks.files(lockBase)){ if (tryLock != null) { int exitCode = MillClientMain.run( lockBase, new Runnable() { @Override public void run() { try{ initServer(lockBase, setJnaNoSys); }catch(Exception e){ throw new RuntimeException(e); } } }, locks, System.in, System.out, System.err, args, env ); return exitCode; } } finally{ } } throw new Exception("Reached max process limit: " + 5); } public static int run(String lockBase, Runnable initServer, Locks locks, InputStream stdin, OutputStream stdout, OutputStream stderr, String[] args, Map env) throws Exception{ try(FileOutputStream f = new FileOutputStream(lockBase + "/run")){ f.write(System.console() != null ? 1 : 0); Util.writeString(f, System.getProperty("MILL_VERSION")); Util.writeArgs(args, f); Util.writeMap(env, f); } 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 && Util.isWindows) Thread.sleep(1000); Socket ioSocket = null; long retryStart = System.currentTimeMillis(); while(ioSocket == null && System.currentTimeMillis() - retryStart < 1000){ try{ ioSocket = Util.isWindows? new Win32NamedPipeSocket(Util.WIN32_PIPE_PREFIX + new File(lockBase).getName()) : new UnixDomainSocket(lockBase + "/io"); }catch(Throwable e){ Thread.sleep(1); } } if (ioSocket == null){ throw new Exception("Failed to connect to server"); } InputStream outErr = ioSocket.getInputStream(); OutputStream in = ioSocket.getOutputStream(); ProxyStreamPumper outPump = new ProxyStreamPumper(outErr, stdout, stderr); InputPumper inPump = new InputPumper(stdin, in, true); Thread outThread = new Thread(outPump); outThread.setDaemon(true); Thread inThread = new Thread(inPump); inThread.setDaemon(true); outThread.start(); inThread.start(); locks.serverLock.await(); try(FileInputStream fos = new FileInputStream(lockBase + "/exitCode")){ return Integer.parseInt(new BufferedReader(new InputStreamReader(fos)).readLine()); } catch(Throwable e){ return 1; } finally{ ioSocket.close(); } } }