/*
* Copyright 2017-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.jvm.java;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.RuleKeyAppendable;
import com.facebook.buck.rules.RuleKeyObjectSink;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.util.MoreCollectors;
import com.facebook.buck.util.immutables.BuckStyleImmutable;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.immutables.value.Value;
/**
* Information for annotation processing.
*
* <p>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.
*/
@Value.Immutable
@BuckStyleImmutable
abstract class AbstractAnnotationProcessingParams implements RuleKeyAppendable {
public static final AnnotationProcessingParams EMPTY =
AnnotationProcessingParams.builder()
.setOwnerTarget(null)
.setProjectFilesystem(null)
.setModernProcessors(ImmutableList.of())
.setParameters(ImmutableSortedSet.of())
.setProcessOnly(false)
.build();
@Nullable
protected abstract BuildTarget getOwnerTarget();
@Nullable
protected abstract ProjectFilesystem getProjectFilesystem();
protected abstract Set<String> getLegacySafeAnnotationProcessors();
protected abstract ImmutableList<BuildRule> getLegacyAnnotationProcessorDeps();
@Value.NaturalOrder
protected abstract ImmutableSortedSet<String> getLegacyAnnotationProcessorNames();
@Value.Lazy
protected ImmutableList<JavacPluginProperties> getLegacyProcessors() {
JavacPluginProperties.Builder legacySafeProcessorsBuilder =
JavacPluginProperties.builder()
.setCanReuseClassLoader(true)
.setDoesNotAffectAbi(false)
.setSupportsAbiGenerationFromSource(false)
.setProcessorNames(
Sets.intersection(
getLegacyAnnotationProcessorNames(), getLegacySafeAnnotationProcessors()));
JavacPluginProperties.Builder legacyUnsafeProcessorsBuilder =
JavacPluginProperties.builder()
.setCanReuseClassLoader(false)
.setDoesNotAffectAbi(false)
.setSupportsAbiGenerationFromSource(false)
.setProcessorNames(
Sets.difference(
getLegacyAnnotationProcessorNames(), getLegacySafeAnnotationProcessors()));
for (BuildRule dep : getLegacyAnnotationProcessorDeps()) {
legacySafeProcessorsBuilder.addDep(dep);
legacyUnsafeProcessorsBuilder.addDep(dep);
}
JavacPluginProperties legacySafeProcessors = legacySafeProcessorsBuilder.build();
JavacPluginProperties legacyUnsafeProcessors = legacyUnsafeProcessorsBuilder.build();
ImmutableList.Builder<JavacPluginProperties> resultBuilder = ImmutableList.builder();
if (!legacySafeProcessors.isEmpty()) {
resultBuilder.add(legacySafeProcessors);
}
if (!legacyUnsafeProcessors.isEmpty()) {
resultBuilder.add(legacyUnsafeProcessors);
}
return resultBuilder.build();
}
protected abstract ImmutableList<ResolvedJavacPluginProperties> getModernProcessors();
@Value.Check
protected void check() {
if (!isEmpty() && getOwnerTarget() != null) {
Preconditions.checkNotNull(getProjectFilesystem());
}
}
private Path getGeneratedSrcFolder() {
ProjectFilesystem filesystem = getProjectFilesystem();
Preconditions.checkNotNull(filesystem);
return BuildTargets.getAnnotationPath(
filesystem, Preconditions.checkNotNull(getOwnerTarget()), "__%s_gen__");
}
public boolean isEmpty() {
return getModernProcessors().isEmpty()
&& getLegacyProcessors().isEmpty()
&& getParameters().isEmpty();
}
public ImmutableList<ResolvedJavacPluginProperties> getAnnotationProcessors(
ProjectFilesystem filesystem, SourcePathResolver resolver) {
if (getLegacyProcessors().isEmpty()) {
return getModernProcessors();
}
return Stream.concat(
getLegacyProcessors()
.stream()
.map(processorGroup -> processorGroup.resolve(filesystem, resolver)),
getModernProcessors().stream())
.collect(MoreCollectors.toImmutableList());
}
@Value.NaturalOrder
public abstract ImmutableSortedSet<String> getParameters();
public ImmutableSortedSet<SourcePath> getInputs() {
return Stream.concat(
getLegacyProcessors().stream().map(JavacPluginProperties::getInputs),
getModernProcessors().stream().map(ResolvedJavacPluginProperties::getInputs))
.flatMap(Collection::stream)
.collect(MoreCollectors.toImmutableSortedSet());
}
@Override
public void appendToRuleKey(RuleKeyObjectSink sink) {
if (!isEmpty()) {
sink.setReflectively("owner", getOwnerTarget())
.setReflectively("legacyProcessors", getLegacyProcessors())
.setReflectively("processors", getModernProcessors())
.setReflectively("parameters", getParameters())
.setReflectively("processOnly", getProcessOnly());
}
}
@Value.Default
protected boolean getProcessOnly() {
return false;
}
@Nullable
public Path getGeneratedSourceFolderName() {
if ((getOwnerTarget() != null) && !isEmpty()) {
return getGeneratedSrcFolder();
} else {
return null;
}
}
}