/*
* Copyright 2014-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.gwt;
import com.facebook.buck.graph.AbstractBreadthFirstTraversal;
import com.facebook.buck.gwt.GwtBinary.Style;
import com.facebook.buck.jvm.java.JavaLibrary;
import com.facebook.buck.jvm.java.JavaOptions;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.CellPathResolver;
import com.facebook.buck.rules.CommonDescriptionArg;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.HasDeclaredDeps;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.util.immutables.BuckStyleImmutable;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.util.Optional;
import org.immutables.value.Value;
public class GwtBinaryDescription implements Description<GwtBinaryDescriptionArg> {
/** Default value for {@link GwtBinaryDescriptionArg#style}. */
private static final Style DEFAULT_STYLE = Style.OBF;
/** Default value for {@link GwtBinaryDescriptionArg#localWorkers}. */
private static final Integer DEFAULT_NUM_LOCAL_WORKERS = Integer.valueOf(2);
/** Default value for {@link GwtBinaryDescriptionArg#draftCompile}. */
private static final Boolean DEFAULT_DRAFT_COMPILE = Boolean.FALSE;
/** Default value for {@link GwtBinaryDescriptionArg#strict}. */
private static final Boolean DEFAULT_STRICT = Boolean.FALSE;
/** This value is taken from GWT's source code: http://bit.ly/1nZtmMv */
private static final Integer DEFAULT_OPTIMIZE = Integer.valueOf(9);
private final JavaOptions javaOptions;
public GwtBinaryDescription(JavaOptions javaOptions) {
this.javaOptions = javaOptions;
}
@Override
public Class<GwtBinaryDescriptionArg> getConstructorArgType() {
return GwtBinaryDescriptionArg.class;
}
@Override
public BuildRule createBuildRule(
TargetGraph targetGraph,
final BuildRuleParams params,
final BuildRuleResolver resolver,
CellPathResolver cellRoots,
GwtBinaryDescriptionArg args) {
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);
final ImmutableSortedSet.Builder<BuildRule> extraDeps = ImmutableSortedSet.naturalOrder();
// Find all of the reachable JavaLibrary rules and grab their associated GwtModules.
final ImmutableSortedSet.Builder<SourcePath> gwtModuleJarsBuilder =
ImmutableSortedSet.naturalOrder();
ImmutableSortedSet<BuildRule> moduleDependencies = resolver.getAllRules(args.getModuleDeps());
new AbstractBreadthFirstTraversal<BuildRule>(moduleDependencies) {
@Override
public ImmutableSet<BuildRule> visit(BuildRule rule) {
if (!(rule instanceof JavaLibrary)) {
return ImmutableSet.of();
}
// If the java library doesn't generate any output, it doesn't contribute a GwtModule
JavaLibrary javaLibrary = (JavaLibrary) rule;
if (javaLibrary.getSourcePathToOutput() == null) {
return rule.getBuildDeps();
}
BuildTarget gwtModuleTarget =
BuildTargets.createFlavoredBuildTarget(
javaLibrary.getBuildTarget().checkUnflavored(), JavaLibrary.GWT_MODULE_FLAVOR);
Optional<BuildRule> gwtModule = resolver.getRuleOptional(gwtModuleTarget);
if (!gwtModule.isPresent() && javaLibrary.getSourcePathToOutput() != null) {
ImmutableSortedSet<SourcePath> filesForGwtModule =
ImmutableSortedSet.<SourcePath>naturalOrder()
.addAll(javaLibrary.getSources())
.addAll(javaLibrary.getResources())
.build();
ImmutableSortedSet<BuildRule> deps =
ImmutableSortedSet.copyOf(ruleFinder.filterBuildRuleInputs(filesForGwtModule));
BuildRule module =
resolver.addToIndex(
new GwtModule(
params
.withBuildTarget(gwtModuleTarget)
.copyReplacingDeclaredAndExtraDeps(
Suppliers.ofInstance(deps),
Suppliers.ofInstance(ImmutableSortedSet.of())),
ruleFinder,
filesForGwtModule));
gwtModule = Optional.of(module);
}
// Note that gwtModule could be absent if javaLibrary is a rule with no srcs of its own,
// but a rule that exists only as a collection of deps.
if (gwtModule.isPresent()) {
extraDeps.add(gwtModule.get());
gwtModuleJarsBuilder.add(
Preconditions.checkNotNull(gwtModule.get().getSourcePathToOutput()));
}
// Traverse all of the deps of this rule.
return rule.getBuildDeps();
}
}.start();
return new GwtBinary(
params.copyReplacingExtraDeps(Suppliers.ofInstance(extraDeps.build())),
args.getModules(),
javaOptions.getJavaRuntimeLauncher(),
args.getVmArgs(),
args.getStyle().orElse(DEFAULT_STYLE),
args.getDraftCompile().orElse(DEFAULT_DRAFT_COMPILE),
args.getOptimize().orElse(DEFAULT_OPTIMIZE),
args.getLocalWorkers().orElse(DEFAULT_NUM_LOCAL_WORKERS),
args.getStrict().orElse(DEFAULT_STRICT),
args.getExperimentalArgs(),
gwtModuleJarsBuilder.build());
}
@BuckStyleImmutable
@Value.Immutable
interface AbstractGwtBinaryDescriptionArg extends CommonDescriptionArg, HasDeclaredDeps {
@Value.NaturalOrder
ImmutableSortedSet<String> getModules();
@Value.NaturalOrder
ImmutableSortedSet<BuildTarget> getModuleDeps();
/** In practice, these may be values such as {@code -Xmx512m}. */
ImmutableList<String> getVmArgs();
/** This will be passed to the GWT Compiler's {@code -style} flag. */
Optional<Style> getStyle();
/** If {@code true}, the GWT Compiler's {@code -draftCompile} flag will be set. */
Optional<Boolean> getDraftCompile();
/** This will be passed to the GWT Compiler's {@code -optimize} flag. */
Optional<Integer> getOptimize();
/** This will be passed to the GWT Compiler's {@code -localWorkers} flag. */
Optional<Integer> getLocalWorkers();
/** If {@code true}, the GWT Compiler's {@code -strict} flag will be set. */
Optional<Boolean> getStrict();
/**
* In practice, these may be values such as {@code -XenableClosureCompiler}, {@code
* -XdisableClassMetadata}, {@code -XdisableCastChecking}, or {@code -XfragmentMerge}.
*/
ImmutableList<String> getExperimentalArgs();
}
}