/*
* 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.android;
import com.facebook.buck.graph.AbstractBreadthFirstTraversal;
import com.facebook.buck.jvm.java.JavaLibrary;
import com.facebook.buck.jvm.java.JavaTest;
import com.facebook.buck.rules.BuildRule;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
public class UnsortedAndroidResourceDeps {
private static final ImmutableSet<Class<? extends BuildRule>> TRAVERSABLE_TYPES =
ImmutableSet.of(
AndroidBinary.class,
AndroidInstrumentationApk.class,
AndroidLibrary.class,
AndroidResource.class,
ApkGenrule.class,
JavaLibrary.class,
JavaTest.class,
RobolectricTest.class);
public interface Callback {
public void onRuleVisited(BuildRule rule, Set<BuildRule> depsToVisit);
}
private final ImmutableSet<HasAndroidResourceDeps> resourceDeps;
public UnsortedAndroidResourceDeps(ImmutableSet<HasAndroidResourceDeps> resourceDeps) {
this.resourceDeps = resourceDeps;
}
public ImmutableSet<HasAndroidResourceDeps> getResourceDeps() {
return resourceDeps;
}
/**
* Returns transitive android resource deps which are _not_ sorted topologically, only to be used
* when the order of the resource rules does not matter, for instance, when graph enhancing
* UberRDotJava, DummyRDotJava, AaptPackageResources where we only need the deps to correctly
* order the execution of those buildables.
*/
public static UnsortedAndroidResourceDeps createFrom(
Collection<BuildRule> rules, final Optional<Callback> callback) {
final ImmutableSet.Builder<HasAndroidResourceDeps> androidResources = ImmutableSet.builder();
// This visitor finds all AndroidResourceRules that are reachable from the specified rules via
// rules with types in the TRAVERSABLE_TYPES collection.
AbstractBreadthFirstTraversal<BuildRule> visitor =
new AbstractBreadthFirstTraversal<BuildRule>(rules) {
@Override
public Set<BuildRule> visit(BuildRule rule) {
HasAndroidResourceDeps androidResourceRule = null;
if (rule instanceof HasAndroidResourceDeps) {
androidResourceRule = (HasAndroidResourceDeps) rule;
}
if (androidResourceRule != null && androidResourceRule.getRes() != null) {
androidResources.add(androidResourceRule);
}
// Only certain types of rules should be considered as part of this traversal.
// For JavaLibrary rules, we need to grab the deps directly from the rule and not from
// the BuildRuleParams object. BuildRuleParams may hold ABI rules which don't allow
// us to properly traverse and locate the transitive android resource deps
Set<BuildRule> depsToVisit;
if (rule instanceof JavaLibrary) {
depsToVisit = ((JavaLibrary) rule).getDepsForTransitiveClasspathEntries();
} else {
depsToVisit =
TRAVERSABLE_TYPES.contains(rule.getClass())
? rule.getBuildDeps()
: ImmutableSet.of();
}
if (callback.isPresent()) {
callback.get().onRuleVisited(rule, depsToVisit);
}
return depsToVisit;
}
};
visitor.start();
return new UnsortedAndroidResourceDeps(androidResources.build());
}
}