blob: d24772502c877054a1dcd22e2706c7c6a2467dc4 [file] [log] [blame]
/*
* 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;
}
}