blob: 0bc84b357fda4c7a62471c17b6c1b2234c753103 [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.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.rules.RuleKeyAppendable;
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.nio.file.Path;
import java.nio.file.Paths;
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 RuleKeyAppendable {
public static final AnnotationProcessingParams EMPTY = new AnnotationProcessingParams(
/* owner target */ null,
/* project filesystem */ null,
ImmutableSet.<Path>of(),
ImmutableSet.<String>of(),
ImmutableSet.<String>of(),
ImmutableSortedSet.<BuildRule>of(),
false);
@Nullable
private final BuildTarget ownerTarget;
@Nullable
private final ProjectFilesystem filesystem;
private final ImmutableSortedSet<Path> 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,
@Nullable ProjectFilesystem filesystem,
Set<Path> searchPathElements,
Set<String> names,
Set<String> parameters,
Set<BuildRule> rules,
boolean processOnly) {
this.ownerTarget = ownerTarget;
this.filesystem = filesystem;
this.searchPathElements = ImmutableSortedSet.copyOf(searchPathElements);
this.names = ImmutableSortedSet.copyOf(names);
this.parameters = ImmutableSortedSet.copyOf(parameters);
this.rules = ImmutableSortedSet.copyOf(rules);
this.processOnly = processOnly;
if (!isEmpty() && ownerTarget != null) {
Preconditions.checkNotNull(filesystem);
}
}
private Path getGeneratedSrcFolder() {
Preconditions.checkNotNull(filesystem);
return Paths.get(
String.format(
"%s/%s__%s_gen__",
BuckConstant.ANNOTATION_DIR,
Preconditions.checkNotNull(ownerTarget).getBasePathWithSlash(),
ownerTarget.getShortNameAndFlavorPostfix()));
}
public boolean isEmpty() {
return searchPathElements.isEmpty() && names.isEmpty() && parameters.isEmpty();
}
public ImmutableSortedSet<Path> getSearchPathElements() {
return searchPathElements;
}
public ImmutableSortedSet<String> getNames() {
return names;
}
public ImmutableSortedSet<String> getParameters() {
return parameters;
}
@Override
public RuleKey.Builder appendToRuleKey(RuleKey.Builder builder, String key) {
if (!isEmpty()) {
// searchPathElements is not needed here since it comes from rules, which is appended below.
String owner = (ownerTarget == null) ? null : ownerTarget.getFullyQualifiedName();
builder.setReflectively(key + ".owner", owner)
.setReflectively(key + ".names", names)
.setReflectively(key + ".parameters", parameters)
.setReflectively(key + ".processOnly", processOnly);
ImmutableList.Builder<String> ruleKeyStrings = ImmutableList.builder();
for (BuildRule rule : rules) {
ruleKeyStrings.add(rule.getRuleKey().toString());
}
builder.setReflectively(key + ".annotationProcessorRuleKeys", ruleKeyStrings.build());
}
return builder;
}
public boolean getProcessOnly() {
return processOnly;
}
@Nullable
public Path getGeneratedSourceFolderName() {
if ((ownerTarget != null) && !isEmpty()) {
return getGeneratedSrcFolder();
} else {
return null;
}
}
public static class Builder {
@Nullable
private BuildTarget ownerTarget;
@Nullable
private ProjectFilesystem filesystem;
private Set<BuildRule> rules = 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(BuildRule rule) {
rules.add(rule);
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 Builder setProjectFilesystem(ProjectFilesystem filesystem) {
this.filesystem = filesystem;
return this;
}
public AnnotationProcessingParams build() {
if (names.isEmpty() && rules.isEmpty() && parameters.isEmpty()) {
return EMPTY;
}
Set<Path> searchPathElements = Sets.newHashSet();
for (BuildRule rule : this.rules) {
if (rule.getClass().isAnnotationPresent(BuildsAnnotationProcessor.class)) {
Path pathToOutput = rule.getPathToOutputFile();
if (pathToOutput != null) {
searchPathElements.add(pathToOutput);
}
} else if (rule instanceof HasClasspathEntries) {
searchPathElements.addAll(
((HasClasspathEntries) rule).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,
rule.getFullyQualifiedName());
}
}
return new AnnotationProcessingParams(
ownerTarget,
filesystem,
searchPathElements,
names,
parameters,
ImmutableSortedSet.copyOf(this.rules),
processOnly);
}
}
}