| /* |
| * Copyright 2012-present Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| * not use this file except in compliance with the License. You may obtain |
| * a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package com.facebook.buck.java; |
| |
| import com.facebook.buck.step.ExecutionContext; |
| import com.facebook.buck.step.Step; |
| import com.facebook.buck.model.AnnotationProcessingData; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Preconditions; |
| import com.google.common.base.Supplier; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| |
| import java.io.File; |
| import java.io.PrintWriter; |
| import java.io.Writer; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| import javax.tools.Diagnostic; |
| import javax.tools.DiagnosticCollector; |
| import javax.tools.JavaCompiler; |
| import javax.tools.JavaFileObject; |
| import javax.tools.StandardJavaFileManager; |
| import javax.tools.ToolProvider; |
| |
| public class JavacInMemoryStep implements Step { |
| |
| private final File outputDirectory; |
| |
| private final Set<String> javaSourceFilePaths; |
| |
| private final Supplier<String> bootclasspathSupplier; |
| |
| private final AnnotationProcessingData annotationProcessingData; |
| |
| private final String sourceLevel; |
| |
| private final String targetLevel; |
| |
| protected final ImmutableSet<String> classpathEntries; |
| |
| public JavacInMemoryStep( |
| String outputDirectory, |
| Set<String> javaSourceFilePaths, |
| Set<String> classpathEntries, |
| Supplier<String> bootclasspathSupplier, |
| AnnotationProcessingData annotationProcessingData) { |
| |
| this( |
| outputDirectory, |
| javaSourceFilePaths, |
| classpathEntries, |
| bootclasspathSupplier, |
| annotationProcessingData, |
| JavacOptionsUtil.DEFAULT_SOURCE_LEVEL, |
| JavacOptionsUtil.DEFAULT_TARGET_LEVEL); |
| } |
| |
| public JavacInMemoryStep( |
| String outputDirectory, |
| Set<String> javaSourceFilePaths, |
| Set<String> classpathEntries, |
| Supplier<String> bootclasspathSupplier, |
| AnnotationProcessingData annotationProcessingData, |
| String sourceLevel, |
| String targetLevel) { |
| Preconditions.checkNotNull(outputDirectory); |
| this.outputDirectory = new File(outputDirectory); |
| this.javaSourceFilePaths = ImmutableSet.copyOf(javaSourceFilePaths); |
| this.classpathEntries = ImmutableSet.copyOf(classpathEntries); |
| this.bootclasspathSupplier = Preconditions.checkNotNull(bootclasspathSupplier); |
| this.annotationProcessingData = Preconditions.checkNotNull(annotationProcessingData); |
| this.sourceLevel = Preconditions.checkNotNull(sourceLevel); |
| this.targetLevel = Preconditions.checkNotNull(targetLevel); |
| } |
| |
| /** |
| * This is public for testing purposes and is not intended for use outside this class. |
| * |
| * Returns a list of command-line options to pass to javac. These options reflect |
| * the configuration of this javac command. |
| * |
| * @param context the ExecutionContext with in which javac will run |
| * @return list of String command-line options. |
| */ |
| public ImmutableList<String> getOptions(ExecutionContext context, |
| Set<String> buildClasspathEntries) { |
| ImmutableList.Builder<String> builder = ImmutableList.builder(); |
| JavacOptionsUtil.addOptions(builder, |
| context, |
| outputDirectory, |
| buildClasspathEntries, |
| bootclasspathSupplier, |
| annotationProcessingData, |
| sourceLevel, |
| targetLevel); |
| return builder.build(); |
| } |
| |
| @Override |
| public final int execute(ExecutionContext context) { |
| |
| return executeBuild(context); |
| } |
| |
| protected int executeBuild(ExecutionContext context) { |
| return buildWithClasspath(context, ImmutableSet.copyOf(classpathEntries)); |
| } |
| |
| protected int buildWithClasspath(ExecutionContext context, |
| Set<String> buildClasspathEntries) { |
| JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); |
| Preconditions.checkNotNull(compiler, |
| "If using JRE instead of JDK, ToolProvider.getSystemJavaCompiler() may be null."); |
| StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); |
| DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); |
| List<String> options = getOptions(context, buildClasspathEntries); |
| List<String> classNamesForAnnotationProcessing = ImmutableList.of(); |
| Iterable<? extends JavaFileObject> compilationUnits = |
| fileManager.getJavaFileObjectsFromStrings(javaSourceFilePaths); |
| |
| Writer compilerOutputWriter = new PrintWriter(context.getStdErr()); |
| JavaCompiler.CompilationTask compilationTask = compiler.getTask( |
| compilerOutputWriter, |
| fileManager, |
| diagnostics, |
| options, |
| classNamesForAnnotationProcessing, |
| compilationUnits); |
| // Invoke the compilation and inspect the result. |
| boolean isSuccess = compilationTask.call(); |
| if (isSuccess) { |
| return 0; |
| } else { |
| if (context.getVerbosity().shouldPrintStandardInformation()) { |
| for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { |
| if (!System.getProperty("java.version").startsWith("1.6")) { |
| // TODO(simons): When we finally move the world to Java 7, this is all we need. |
| context.getStdErr().println(diagnostic); |
| } else { |
| // TODO(simons): Warn the user that they're using an EOLd JDK. |
| String newLine = System.getProperty("line.separator", "\n"); |
| StringBuilder message = new StringBuilder(); |
| |
| if (diagnostic.getSource() != null) { |
| message.append(diagnostic.getSource().getName()) |
| .append(":") |
| .append(diagnostic.getLineNumber()) |
| .append(": ").append(diagnostic.getMessage(Locale.getDefault())) |
| .append(newLine); |
| } else { |
| message.append(diagnostic.getMessage(Locale.getDefault())).append(newLine); |
| } |
| context.getStdErr().println(message.toString()); |
| } |
| } |
| } |
| return 1; |
| } |
| } |
| |
| @Override |
| public String getDescription(ExecutionContext context) { |
| Set<String> buildClassPathEntries = classpathEntries; |
| |
| StringBuilder builder = new StringBuilder("javac "); |
| Joiner.on(" ").appendTo(builder, getOptions(context, buildClassPathEntries)); |
| builder.append(" "); |
| Joiner.on(" ").appendTo(builder, javaSourceFilePaths); |
| |
| return builder.toString(); |
| } |
| |
| @Override |
| public String getShortName(ExecutionContext context) { |
| return String.format("javac %s", outputDirectory); |
| } |
| |
| public Set<String> getSrcs() { |
| return javaSourceFilePaths; |
| } |
| |
| } |