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  }