blob: 3316c0916ed031676a8b101e18b5ed97141b57f4 [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.model.BuildTarget;
import com.facebook.buck.rules.AnnotationProcessingData;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.util.BuckConstant;
import com.facebook.buck.util.HumanReadableException;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Information for annotation processing.
*
* Annotation processing involves a set of processors, their classpath(s), and a few other
* command-line options for javac. We want to be able to specify all this various information
* in a BUCK configuration file and use it when we generate the javac command. This facilitates
* threading the information through buck in a more descriptive package rather than passing all
* the components separately.
*/
public class AnnotationProcessingParams implements AnnotationProcessingData {
public final static AnnotationProcessingParams EMPTY = new AnnotationProcessingParams(
null,
ImmutableSet.<String>of(),
ImmutableSet.<String>of(),
ImmutableSet.<String>of(),
ImmutableSortedSet.<BuildRule>of(),
false);
@Nullable
private final BuildTarget ownerTarget;
private final ImmutableSortedSet<String> searchPathElements;
private final ImmutableSortedSet<String> names;
private final ImmutableSortedSet<String> parameters;
private final ImmutableSortedSet<BuildRule> rules;
private final boolean processOnly;
private AnnotationProcessingParams(
@Nullable BuildTarget ownerTarget,
Set<String> searchPathElements,
Set<String> names,
Set<String> parameters,
Set<BuildRule> rules,
boolean processOnly) {
this.ownerTarget = ownerTarget;
this.searchPathElements = ImmutableSortedSet.copyOf(searchPathElements);
this.names = ImmutableSortedSet.copyOf(names);
this.parameters = ImmutableSortedSet.copyOf(parameters);
this.rules = ImmutableSortedSet.copyOf(rules);
this.processOnly = processOnly;
}
private String getGeneratedSrcFolder() {
return String.format("%s/%s__%s_gen__",
BuckConstant.ANNOTATION_DIR,
ownerTarget.getBasePathWithSlash(),
ownerTarget.getShortName());
}
@Override
public boolean isEmpty() {
return searchPathElements.isEmpty() && names.isEmpty() && parameters.isEmpty();
}
@Override
public ImmutableSortedSet<String> getSearchPathElements() {
return searchPathElements;
}
@Override
public ImmutableSortedSet<String> getNames() {
return names;
}
@Override
public ImmutableSortedSet<String> getParameters() {
return parameters;
}
@Override
public RuleKey.Builder appendToRuleKey(RuleKey.Builder builder) throws IOException {
if (!isEmpty()) {
// searchPathElements is not needed here since it comes from rules, which is appended below.
String owner = (ownerTarget == null) ? null : ownerTarget.getFullyQualifiedName();
builder.set("owner", owner)
.set("names", names)
.set("parameters", parameters)
.set("processOnly", processOnly);
ImmutableList.Builder<String> ruleKeyStrings = ImmutableList.builder();
for (BuildRule rule : rules) {
ruleKeyStrings.add(rule.getRuleKey().toString());
}
builder.set("annotationProcessorRuleKeys", ruleKeyStrings.build());
}
return builder;
}
@Override
public boolean getProcessOnly() {
return processOnly;
}
@Override
@Nullable
public String getGeneratedSourceFolderName() {
if ((ownerTarget != null) && !isEmpty()) {
return getGeneratedSrcFolder();
} else {
return null;
}
}
public static class Builder {
@Nullable
private BuildTarget ownerTarget;
private Set<BuildTarget> targets = Sets.newHashSet();
private Set<String> names = Sets.newHashSet();
private Set<String> parameters = Sets.newHashSet();
private boolean processOnly;
public Builder setOwnerTarget(BuildTarget owner) {
ownerTarget = owner;
return this;
}
public Builder addProcessorBuildTarget(BuildTarget target) {
targets.add(target);
return this;
}
public Builder addAllProcessors(Collection<? extends String> processorNames) {
names.addAll(processorNames);
return this;
}
public Builder addParameter(String parameter) {
parameters.add(parameter);
return this;
}
public Builder setProcessOnly(boolean processOnly) {
this.processOnly = processOnly;
return this;
}
public AnnotationProcessingParams build(BuildRuleResolver ruleResolver) {
Preconditions.checkNotNull(ruleResolver);
if (names.isEmpty() && targets.isEmpty() && parameters.isEmpty()) {
return EMPTY;
}
Set<String> searchPathElements = Sets.newHashSet();
ImmutableSortedSet.Builder<BuildRule> rules = ImmutableSortedSet.naturalOrder();
for (BuildTarget target : targets) {
BuildRule rule = ruleResolver.get(target);
String type = rule.getType().getName();
rules.add(rule);
// We're using raw strings here to avoid circular dependencies.
// TODO(simons): don't use raw strings.
if ("java_binary".equals(type) || "prebuilt_jar".equals(type)) {
String pathToOutput = rule.getBuildable().getPathToOutputFile();
if (pathToOutput != null) {
searchPathElements.add(pathToOutput);
}
} else if (rule instanceof HasClasspathEntries) {
HasClasspathEntries javaLibraryRule = (HasClasspathEntries)rule;
searchPathElements.addAll(javaLibraryRule.getTransitiveClasspathEntries().values());
} else {
throw new HumanReadableException(
"%1$s: Error adding '%2$s' to annotation_processing_deps: " +
"must refer only to prebuilt jar, java binary, or java library targets.",
ownerTarget,
target.getFullyQualifiedName());
}
}
return new AnnotationProcessingParams(
ownerTarget,
searchPathElements,
names,
parameters,
rules.build(),
processOnly);
}
}
}