github.phpd.cn/thought-machine/please@v12.2.0+incompatible/tools/javac_worker/src/build/please/compile/JavaCompiler.java (about) 1 package build.please.compile; 2 3 import build.please.worker.WorkerProto.BuildRequest; 4 import build.please.worker.WorkerProto.BuildResponse; 5 6 import java.io.File; 7 import java.io.IOException; 8 import java.io.StringWriter; 9 import java.nio.ByteBuffer; 10 import java.nio.ByteOrder; 11 import java.nio.file.Files; 12 import java.util.ArrayList; 13 import java.util.Arrays; 14 import java.util.concurrent.ExecutorService; 15 import java.util.concurrent.Executors; 16 17 import javax.tools.JavaFileObject; 18 import javax.tools.StandardJavaFileManager; 19 import javax.tools.ToolProvider; 20 21 public class JavaCompiler { 22 /** 23 * run reads requests from stdin and sends them to stdout until they are closed. 24 */ 25 public void run() { 26 ExecutorService executor = Executors.newFixedThreadPool(8); 27 final byte[] readBuffer = new byte[4]; 28 final byte[] writeBuffer = new byte[4]; 29 while (true) { 30 try { 31 readStdin(readBuffer); 32 ByteBuffer bb = ByteBuffer.wrap(readBuffer); 33 bb.order(ByteOrder.LITTLE_ENDIAN); 34 final byte[] pb = new byte[bb.getInt()]; 35 readStdin(pb); 36 executor.submit(new Runnable() { 37 public void run() { 38 try { 39 BuildResponse response = build(BuildRequest.parseFrom(pb)); 40 byte[] arr = response.toByteArray(); 41 synchronized (writeBuffer) { 42 ByteBuffer bb = ByteBuffer.wrap(writeBuffer); 43 bb.order(ByteOrder.LITTLE_ENDIAN); 44 bb.putInt(arr.length); 45 System.out.write(bb.array()); 46 System.out.write(arr); 47 } 48 } catch (IOException ex) { 49 System.err.printf("I/O error: %s", ex.toString()); 50 } 51 } 52 }); 53 } catch (IOException ex) { 54 System.err.printf("I/O error: %s", ex.toString()); 55 break; 56 } 57 } 58 } 59 60 /** 61 * readStdin wraps System.in.read to convert EOF to an exception. 62 */ 63 private void readStdin(byte[] b) throws IOException { 64 if (System.in.read(b) == -1) { 65 throw new IOException("EOF on stdin, exiting"); 66 } 67 } 68 69 /** 70 * build handles building a single build rule. 71 */ 72 public BuildResponse build(BuildRequest request) throws IOException { 73 try { 74 return reallyBuild(request); 75 } catch (Exception ex) { 76 return BuildResponse.newBuilder() 77 .setRule(request.getRule()) 78 .setSuccess(false) 79 .addMessages(ex.toString()) 80 .build(); 81 } 82 } 83 84 /** 85 * newCompiler creates a new compiler instance. 86 * This is added to allow subclasses to define their own compiler supplier (e.g. ErrorProne). 87 */ 88 public javax.tools.JavaCompiler newCompiler(BuildRequest request) { 89 return ToolProvider.getSystemJavaCompiler(); 90 } 91 92 private BuildResponse reallyBuild(BuildRequest request) throws IOException { 93 BuildResponse.Builder builder = BuildResponse.newBuilder() 94 .setRule(request.getRule()); 95 // Try to create the output directory 96 File file = new File(request.getTempDir() + "/_tmp/META-INF"); 97 if (!file.mkdirs()) { 98 return builder 99 .addMessages("Failed to create directory " + file.getPath()) 100 .setSuccess(false) 101 .build(); 102 } 103 String tmpDir = request.getTempDir() + "/_tmp"; 104 DiagnosticReporter reporter = new DiagnosticReporter(builder); 105 try(StringWriter writer = new StringWriter()) { 106 javax.tools.JavaCompiler compiler = newCompiler(request); 107 StandardJavaFileManager fileManager = compiler.getStandardFileManager(reporter, null, null); 108 ArrayList<String> srcs = new ArrayList<>(); 109 for (String src : request.getSrcsList()) { 110 srcs.add(src.startsWith("/") ? src : request.getTempDir() + "/" + src); 111 } 112 Iterable<? extends JavaFileObject> compilationUnits; 113 ArrayList<String> opts = new ArrayList<>(); 114 opts.addAll(Arrays.asList( 115 "-d", tmpDir, 116 "-s", tmpDir, 117 "-sourcepath", request.getTempDir())); 118 opts.addAll(request.getOptsList()); 119 if (opts.contains("--src_dir")) { 120 // Special flag that indicates that the sources are actually a directory and we should compile everything in it. 121 opts.remove("--src_dir"); 122 FileFinder finder = new FileFinder(".java"); 123 Files.walkFileTree(new File(request.getTempDir() + "/" + request.getSrcs(0)).toPath(), finder); 124 compilationUnits = fileManager.getJavaFileObjectsFromStrings(finder.getFiles()); 125 } else { 126 compilationUnits = fileManager.getJavaFileObjectsFromStrings(srcs); 127 } 128 129 // Find any .jar files and add them to the classpath or module-path 130 FileFinder finder = new FileFinder(".jar"); 131 Files.walkFileTree(new File(request.getTempDir()).toPath(), finder); 132 133 if (opts.contains("--modular")) { 134 if (!areModulesSupported()) { 135 return builder.addMessages("The system java compiler does not support modules") 136 .setSuccess(false) 137 .build(); 138 } 139 // Special flag that indicates that we're trying to use the new java 9 modular JVM 140 opts.remove("--modular"); 141 opts.add("--module-path"); 142 } else { 143 opts.add("-classpath"); 144 } 145 opts.add(finder.joinFiles(':')); 146 return builder 147 .setSuccess(compiler.getTask(writer, fileManager, reporter, opts, null, compilationUnits).call()) 148 .addMessages(writer.toString()) 149 .build(); 150 } 151 } 152 153 private boolean areModulesSupported() { 154 // The java version scheme changed in java 9 from '1.<major>.<minor>' to '<major>.<minor>' 155 return !System.getProperty("java.version").startsWith("1."); 156 } 157 158 public static void main(String[] args) { 159 JavaCompiler compiler = new JavaCompiler(); 160 compiler.run(); 161 } 162 }