Skip to content

Commit

Permalink
Add support for exported_deps for aar & jar prebuilts. (#836)
Browse files Browse the repository at this point in the history
To make generated buck files small and less verbose we can use `exported_deps` for api dependencies. deps of prebuilts are exported by default (i.e dependees of a prebuilt will also get prebuilt's dependencies in it's compile classpath). 

To enable this make the below changes in okbuck extension:
```
okbuck {
    externalDependencies {
        resolutionAction = "latest"
        enableExportedDeps = true
    }
}
```

Note: this only works when `resolutionAction` is either `latest` or `single`.


example generated buck files:
```
// in .okbuck/ext/androidx/activity/BUCK
load('//.okbuck/defs:okbuck_prebuilt.bzl', 'okbuck_prebuilt')

okbuck_prebuilt(
    name = 'activity.aar',
    maven_coords = 'androidx.activity:activity:aar:1.0.0-alpha04',
    sha256 = '4a2c0a2e53933075fa6979b8921a8c7047ec60d5e3906d774f77bd598842aad9',
    sources_sha256 = '6127d87d0d7402172341c6c30591fdb05f7c1e63ec29e79be88d1f8fe46ca762',
    deps = [
        '//3rdparty/jvm/androidx/annotation:annotation.jar',
        '//3rdparty/jvm/androidx/core:core.aar',
        '//3rdparty/jvm/androidx/lifecycle:lifecycle-runtime.aar',
        '//3rdparty/jvm/androidx/lifecycle:lifecycle-viewmodel.aar',
        '//3rdparty/jvm/androidx/savedstate:savedstate-bundle.aar',
    ],
)


// in .okbuck/ext/androidx/lifecycle/BUCK
load('//.okbuck/defs:okbuck_prebuilt.bzl', 'okbuck_prebuilt')

okbuck_prebuilt(
    name = 'lifecycle-runtime.aar',
    maven_coords = 'androidx.lifecycle:lifecycle-runtime:aar:2.0.0',
    sha256 = 'e4afc9e636183f6f3e0edf1cf46121a492ffd2c673075bb07f55c7a99dd43cfb',
    sources_sha256 = '472d99cf093b3b65d24a5707138ce51b160eb81a0ed59095ca8c8e0883ab1524',
    deps = [
        '//3rdparty/jvm/androidx/annotation:annotation.jar',
        '//3rdparty/jvm/androidx/arch/core:core-common.jar',
        '//3rdparty/jvm/androidx/lifecycle:lifecycle-common.jar',
    ],
)

// in an android library buck file
android_library (
    name = 'src_release',
    deps = [
         '//.okbuck/ext/androidx/activity:activity.aar'
    ]
```

In the above android_library we don't need to specify `lifecycle-runtime.aar` or `lifecycle-common.jar` as a dependency since that would be coming transitively. 

To enable this change, make sure you have pulled in facebook/buck#2247 PR on the buck side.
  • Loading branch information
raviagarwal7 authored Apr 20, 2019
1 parent ee2d692 commit 7cca254
Show file tree
Hide file tree
Showing 22 changed files with 395 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import com.uber.okbuck.composer.jvm.JvmBuckRuleComposer;
import com.uber.okbuck.core.model.android.AndroidAppTarget;
import com.uber.okbuck.core.model.android.AndroidTarget;
import com.uber.okbuck.core.model.base.Target;
import java.util.Set;
import java.util.stream.Collectors;

public abstract class AndroidBuckRuleComposer extends JvmBuckRuleComposer {

Expand Down Expand Up @@ -53,4 +56,12 @@ public static String instrumentation(AndroidAppTarget target) {
static String instrumentationTest(AndroidAppTarget target) {
return "instrumentation_" + target.getName() + "_test";
}

static Set<String> resources(Set<Target> targets) {
return targets
.stream()
.filter(targetDep -> targetDep instanceof AndroidTarget)
.map(targetDep -> resRule((AndroidTarget) targetDep))
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.google.common.collect.ImmutableSet;
import com.uber.okbuck.composer.base.BuckRuleComposer;
import com.uber.okbuck.core.model.android.AndroidLibTarget;
import com.uber.okbuck.core.model.android.AndroidTarget;
import com.uber.okbuck.core.model.base.RuleType;
import com.uber.okbuck.core.model.jvm.JvmTarget;
import com.uber.okbuck.core.util.D8Util;
Expand Down Expand Up @@ -34,13 +33,8 @@ public static Rule compose(
Set<String> libraryDeps = new HashSet<>(deps);
libraryDeps.addAll(external(target.getExternalDeps(false)));
libraryDeps.addAll(targets(target.getTargetDeps(false)));
libraryDeps.addAll(
target
.getTargetDeps(false)
.stream()
.filter(targetDep -> targetDep instanceof AndroidTarget)
.map(targetDep -> resRule((AndroidTarget) targetDep))
.collect(Collectors.toSet()));
libraryDeps.addAll(resources(target.getTargetDeps(false)));
libraryDeps.addAll(resources(target.getTargetExportedDeps(false)));

List<String> libraryAptDeps = new ArrayList<>();
libraryAptDeps.addAll(externalApt(target.getExternalAptDeps(false)));
Expand All @@ -54,6 +48,7 @@ public static Rule compose(
Set<String> libraryExportedDeps = new HashSet<>();
libraryExportedDeps.addAll(external(target.getExternalExportedDeps(false)));
libraryExportedDeps.addAll(targets(target.getTargetExportedDeps(false)));
libraryExportedDeps.addAll(aidlRuleNames);

List<String> testTargets = new ArrayList<>();
if (target.getRobolectricEnabled() && !target.getTest().getSources().isEmpty()) {
Expand All @@ -80,7 +75,6 @@ public static Rule compose(
.sourceCompatibility(target.getSourceCompatibility())
.targetCompatibility(target.getTargetCompatibility())
.testTargets(testTargets)
.exportedDeps(aidlRuleNames)
.excludes(appClass != null ? ImmutableSet.of(appClass) : ImmutableSet.of())
.generateR2(target.getGenerateR2())
.options(target.getMain().getCustomOptions());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
import com.uber.okbuck.core.model.base.RuleType;
import com.uber.okbuck.template.android.ResourceRule;
import com.uber.okbuck.template.core.Rule;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Set;

public final class AndroidResourceRuleComposer extends AndroidBuckRuleComposer {

Expand All @@ -16,24 +15,22 @@ private AndroidResourceRuleComposer() {
}

public static Rule compose(AndroidTarget target, List<String> extraResDeps) {
List<String> resDeps = new ArrayList<>();
resDeps.addAll(external(new HashSet<>(target.getMain().getExternalAarDeps())));
resDeps.addAll(
target
.getTargetDeps(false)
.stream()
.filter(targetDep -> targetDep instanceof AndroidTarget)
.map(targetDep -> resRule((AndroidTarget) targetDep))
.collect(Collectors.toSet()));

Set<String> resDeps = new HashSet<>();
resDeps.addAll(external(target.getExternalAarDeps(false)));
resDeps.addAll(resources(target.getTargetDeps(false)));
resDeps.addAll(extraResDeps);

Set<String> resExportedDeps = new HashSet<>();
resExportedDeps.addAll(external(target.getExternalExportedAarDeps(false)));
resExportedDeps.addAll(resources(target.getTargetExportedDeps(false)));

return new ResourceRule()
.pkg(target.getResPackage())
.res(target.getResDirs())
.projectRes(target.getProjectResDir())
.assets(target.getAssetDirs())
.resourceUnion(target.getOkbuck().useResourceUnion())
.exportedDeps(resExportedDeps)
.defaultVisibility()
.ruleType(RuleType.ANDROID_RESOURCE.getBuckName())
.deps(resDeps)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ public static Rule compose(AndroidAppTarget target) {
deps.add(":" + buildConfig(target));

Set<String> libraryAptDeps = new LinkedHashSet<>();
libraryAptDeps.addAll(externalApt(target.getApt().getExternalJarDeps()));
libraryAptDeps.addAll(targetsApt(target.getApt().getTargetDeps()));

libraryAptDeps.addAll(externalApt(target.getExternalAptDeps(false)));
libraryAptDeps.addAll(targetsApt(target.getTargetAptDeps(false)));

Set<String> providedDeps = new LinkedHashSet<>();
providedDeps.add(D8Util.RT_STUB_JAR_RULE);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.uber.okbuck.composer.java;

import static com.uber.okbuck.core.dependency.ExternalDependency.filterJar;

import com.google.common.collect.ImmutableSet;
import com.uber.okbuck.composer.jvm.JvmBuckRuleComposer;
import com.uber.okbuck.core.model.base.RuleType;
Expand Down Expand Up @@ -33,7 +35,7 @@ public static List<Rule> compose(Collection<Scope> scopeList) {
.map(
scope -> {
ImmutableSet.Builder<String> depsBuilder = new ImmutableSet.Builder<>();
depsBuilder.addAll(externalApt(scope.getExternalJarDeps()));
depsBuilder.addAll(externalApt(filterJar(scope.getExternalDeps())));
depsBuilder.addAll(targetsApt(scope.getTargetDeps()));

return new JavaAnnotationProcessorRule()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static com.uber.okbuck.core.dependency.BaseExternalDependency.AAR;
import static com.uber.okbuck.core.dependency.BaseExternalDependency.JAR;

import com.google.common.collect.ImmutableList;
import com.uber.okbuck.composer.jvm.JvmBuckRuleComposer;
import com.uber.okbuck.core.dependency.ExternalDependency;
import com.uber.okbuck.core.model.base.RuleType;
Expand Down Expand Up @@ -45,20 +44,16 @@ public static List<Rule> compose(Collection<ExternalDependency> dependencies) {
source = null;
}

ImmutableList.Builder<Rule> rulesBuilder = ImmutableList.builder();
rulesBuilder.add(
new NativePrebuilt()
.prebuiltType(ruleType.getProperties().get(0))
.prebuilt(dependency.getDependencyFileName())
.mavenCoords(dependency.getMavenCoords())
.enableJetifier(dependency.enableJetifier())
.source(source)
.ruleType(ruleType.getBuckName())
.name(dependency.getTargetName()));

return rulesBuilder.build();
return new NativePrebuilt()
.prebuiltType(ruleType.getProperties().get(0))
.prebuilt(dependency.getDependencyFileName())
.mavenCoords(dependency.getMavenCoords())
.enableJetifier(dependency.enableJetifier())
.source(source)
.ruleType(ruleType.getBuckName())
.deps(dependency.getDeps())
.name(dependency.getTargetName());
})
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ public static List<Rule> compose(Collection<ExternalDependency> dependencies) {
.getRealSourceFile()
.ifPresent(file -> rule.sourcesSha256(DependencyUtils.shaSum256(file)));

rule.name(dependency.getTargetName());
rule.ruleType(RuleType.PREBUILT.getBuckName());
rule.ruleType(RuleType.PREBUILT.getBuckName())
.deps(external(dependency.getDeps()))
.name(dependency.getTargetName());

return rule;
})
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package com.uber.okbuck.core.dependency;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.uber.okbuck.core.manager.DependencyManager;
import com.uber.okbuck.core.model.base.Scope;
import com.uber.okbuck.core.util.ProjectUtil;
import com.uber.okbuck.extension.ExternalDependenciesExtension;
import com.uber.okbuck.extension.JetifierExtension;
import com.uber.okbuck.extension.OkBuckExtension;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -23,6 +21,7 @@
import org.apache.commons.io.IOUtils;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencySet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -44,13 +43,9 @@ public DependencyCache(
this.skipPrebuilt = skipPrebuilt;

if (forcedConfiguration != null) {
Scope.builder(project)
.configuration(forcedConfiguration)
.build()
.getAllExternal()
build(forcedConfiguration)
.forEach(
dependency -> {
get(dependency);
forcedDeps.put(dependency.getVersionless(), dependency);
});
}
Expand Down Expand Up @@ -81,6 +76,16 @@ public final ExternalDependency get(ExternalDependency externalDependency) {
return dependency;
}

public final void addDependencies(DependencySet dependencySet) {
this.dependencyManager.addDependencies(
dependencySet
.stream()
.filter(dependency -> dependency instanceof org.gradle.api.artifacts.ExternalDependency)
.filter(dependency -> dependency.getGroup() != null && dependency.getVersion() != null)
.map(dependency -> (org.gradle.api.artifacts.ExternalDependency) dependency)
.collect(Collectors.toSet()));
}

/**
* Get the list of annotation processor classes provided by a dependency.
*
Expand All @@ -90,7 +95,6 @@ public final ExternalDependency get(ExternalDependency externalDependency) {
public Set<String> getAnnotationProcessors(ExternalDependency externalDependency) {
ExternalDependency dependency =
forcedDeps.getOrDefault(externalDependency.getVersionless(), externalDependency);
String key = dependency.getTargetName();

try {
String processors =
Expand Down Expand Up @@ -148,32 +152,34 @@ private static String getJarFileContent(File dependencyFile, String filePathStri
return content;
}

public Set<ExternalDependency> build(Configuration configuration) {
return build(Collections.singleton(configuration));
}

/**
* Use this method to populate dependency caches of tools/languages etc. This is not meant to be
* used across multiple threads/gradle task executions which can run in parallel. This method is
* fully synchronous.
*
* @param configurations The set of configurations to materialize into the dependency cache
* @param configuration The configuration to materialize into the dependency cache
*/
private Set<ExternalDependency> build(Set<Configuration> configurations) {
public Set<ExternalDependency> build(Configuration configuration) {
OkBuckExtension okBuckExtension = ProjectUtil.getOkBuckExtension(rootProject);

ExternalDependenciesExtension externalDependenciesExtension =
okBuckExtension.getExternalDependenciesExtension();
JetifierExtension jetifierExtension = okBuckExtension.getJetifierExtension();

return configurations
addDependencies(configuration.getAllDependencies());

return DependencyUtils.resolveExternal(
rootProject, configuration, externalDependenciesExtension, jetifierExtension)
.stream()
.map(
configuration ->
DependencyUtils.resolveExternal(
rootProject, configuration, externalDependenciesExtension, jetifierExtension))
.flatMap(Collection::stream)
.map(this::get)
.collect(Collectors.toSet());
}

private Set<ExternalDependency> build(String configuration) {
Configuration useful = DependencyUtils.useful(configuration, rootProject);

Preconditions.checkNotNull(useful);

return build(useful);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
import com.uber.okbuck.extension.ExternalDependenciesExtension;
import com.uber.okbuck.extension.JetifierExtension;
import java.io.File;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.commons.io.FilenameUtils;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ResolvedDependency;

public final class DependencyFactory {

private static final String LOCAL_GROUP = "local";
public static final String LOCAL_GROUP = "local";

private static final String LOCAL_DEP_VERSION = "1.0.0-LOCAL";

private DependencyFactory() {}
Expand Down Expand Up @@ -84,24 +89,58 @@ public static LocalExternalDependency fromLocal(
}

/**
* Returns a versionless dependency from the given gradle dependency.
* Returns a set of versionless dependencies from the given gradle dependency.
*
* @param dependency gradle dependency
* @return VersionlessDependency object
*/
public static VersionlessDependency fromDependency(Dependency dependency) {
VersionlessDependency.Builder vDependency =
public static Set<VersionlessDependency> fromDependency(
org.gradle.api.artifacts.ExternalDependency dependency) {
VersionlessDependency.Builder vDependencyBuilder =
VersionlessDependency.builder().setName(dependency.getName());

String group = dependency.getGroup();
if (group == null) {
vDependency.setGroup(LOCAL_GROUP);
vDependencyBuilder.setGroup(LOCAL_GROUP);
} else {
vDependency.setGroup(group);
vDependencyBuilder.setGroup(group);
}

// TODO: Add support of specifying classifier
return vDependency.build();
if (dependency.getArtifacts().size() > 0) {
return dependency
.getArtifacts()
.stream()
.map(
dependencyArtifact ->
vDependencyBuilder
.setClassifier(Optional.ofNullable(dependencyArtifact.getClassifier()))
.build())
.collect(Collectors.toSet());
} else {
Set<VersionlessDependency> dependencies = new HashSet<>();
dependencies.add(vDependencyBuilder.build());
return dependencies;
}
}

/**
* Returns a set of versionless dependency from the given gradle resolved dependency.
*
* @param dependency gradle dependency
* @return VersionlessDependency object
*/
public static Set<VersionlessDependency> fromDependency(ResolvedDependency dependency) {
return dependency
.getModuleArtifacts()
.stream()
.map(
resolvedArtifact ->
VersionlessDependency.builder()
.setName(dependency.getModuleName())
.setGroup(dependency.getModuleGroup())
.setClassifier(Optional.ofNullable(resolvedArtifact.getClassifier()))
.build())
.collect(Collectors.toSet());
}

/**
Expand Down
Loading

0 comments on commit 7cca254

Please sign in to comment.