diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidBuckRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidBuckRuleComposer.java index ba9dbdc1a..8142d16b3 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidBuckRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidBuckRuleComposer.java @@ -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 { @@ -53,4 +56,12 @@ public static String instrumentation(AndroidAppTarget target) { static String instrumentationTest(AndroidAppTarget target) { return "instrumentation_" + target.getName() + "_test"; } + + static Set resources(Set targets) { + return targets + .stream() + .filter(targetDep -> targetDep instanceof AndroidTarget) + .map(targetDep -> resRule((AndroidTarget) targetDep)) + .collect(Collectors.toSet()); + } } diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidLibraryRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidLibraryRuleComposer.java index eae16500d..b3cd4b119 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidLibraryRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidLibraryRuleComposer.java @@ -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; @@ -34,13 +33,8 @@ public static Rule compose( Set 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 libraryAptDeps = new ArrayList<>(); libraryAptDeps.addAll(externalApt(target.getExternalAptDeps(false))); @@ -54,6 +48,7 @@ public static Rule compose( Set libraryExportedDeps = new HashSet<>(); libraryExportedDeps.addAll(external(target.getExternalExportedDeps(false))); libraryExportedDeps.addAll(targets(target.getTargetExportedDeps(false))); + libraryExportedDeps.addAll(aidlRuleNames); List testTargets = new ArrayList<>(); if (target.getRobolectricEnabled() && !target.getTest().getSources().isEmpty()) { @@ -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()); diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidResourceRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidResourceRuleComposer.java index 6acb6549a..5cb4d5858 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidResourceRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/android/AndroidResourceRuleComposer.java @@ -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 { @@ -16,24 +15,22 @@ private AndroidResourceRuleComposer() { } public static Rule compose(AndroidTarget target, List extraResDeps) { - List 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 resDeps = new HashSet<>(); + resDeps.addAll(external(target.getExternalAarDeps(false))); + resDeps.addAll(resources(target.getTargetDeps(false))); resDeps.addAll(extraResDeps); + Set 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) diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/android/ExopackageAndroidLibraryRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/android/ExopackageAndroidLibraryRuleComposer.java index 942bf6c66..5b293bdec 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/android/ExopackageAndroidLibraryRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/android/ExopackageAndroidLibraryRuleComposer.java @@ -31,8 +31,9 @@ public static Rule compose(AndroidAppTarget target) { deps.add(":" + buildConfig(target)); Set 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 providedDeps = new LinkedHashSet<>(); providedDeps.add(D8Util.RT_STUB_JAR_RULE); diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/java/JavaAnnotationProcessorRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/java/JavaAnnotationProcessorRuleComposer.java index 6d2a75202..1f308e43b 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/java/JavaAnnotationProcessorRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/java/JavaAnnotationProcessorRuleComposer.java @@ -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; @@ -33,7 +35,7 @@ public static List compose(Collection scopeList) { .map( scope -> { ImmutableSet.Builder depsBuilder = new ImmutableSet.Builder<>(); - depsBuilder.addAll(externalApt(scope.getExternalJarDeps())); + depsBuilder.addAll(externalApt(filterJar(scope.getExternalDeps()))); depsBuilder.addAll(targetsApt(scope.getTargetDeps())); return new JavaAnnotationProcessorRule() diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/java/LocalPrebuiltRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/java/LocalPrebuiltRuleComposer.java index 72849c686..fe1d03de0 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/java/LocalPrebuiltRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/java/LocalPrebuiltRuleComposer.java @@ -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; @@ -45,20 +44,16 @@ public static List compose(Collection dependencies) { source = null; } - ImmutableList.Builder 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()); } } diff --git a/buildSrc/src/main/java/com/uber/okbuck/composer/java/PrebuiltRuleComposer.java b/buildSrc/src/main/java/com/uber/okbuck/composer/java/PrebuiltRuleComposer.java index df6f49f96..7b0bb4235 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/composer/java/PrebuiltRuleComposer.java +++ b/buildSrc/src/main/java/com/uber/okbuck/composer/java/PrebuiltRuleComposer.java @@ -45,8 +45,10 @@ public static List compose(Collection 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()); diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyCache.java b/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyCache.java index 22201f1b8..79d88ca17 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyCache.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyCache.java @@ -1,8 +1,8 @@ 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; @@ -10,8 +10,6 @@ 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; @@ -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; @@ -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); }); } @@ -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. * @@ -90,7 +95,6 @@ public final ExternalDependency get(ExternalDependency externalDependency) { public Set getAnnotationProcessors(ExternalDependency externalDependency) { ExternalDependency dependency = forcedDeps.getOrDefault(externalDependency.getVersionless(), externalDependency); - String key = dependency.getTargetName(); try { String processors = @@ -148,32 +152,34 @@ private static String getJarFileContent(File dependencyFile, String filePathStri return content; } - public Set 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 build(Set configurations) { + public Set 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 build(String configuration) { + Configuration useful = DependencyUtils.useful(configuration, rootProject); + + Preconditions.checkNotNull(useful); + + return build(useful); + } } diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyFactory.java b/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyFactory.java index db6354e5a..1229b6aed 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyFactory.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/dependency/DependencyFactory.java @@ -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() {} @@ -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 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 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 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()); } /** diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/dependency/ExternalDependency.java b/buildSrc/src/main/java/com/uber/okbuck/core/dependency/ExternalDependency.java index 7a6226288..6fbadea7e 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/dependency/ExternalDependency.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/dependency/ExternalDependency.java @@ -12,8 +12,11 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Comparator; +import java.util.HashSet; import java.util.Objects; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.Nullable; import org.gradle.api.artifacts.Dependency; @@ -27,8 +30,8 @@ public class ExternalDependency { private final BaseExternalDependency base; private final Path cachePath; - @Nullable private Path realSourceFilePath; private boolean enableJetifier; + private Set dependencies = new HashSet<>(); public static Comparator compareByName = (o1, o2) -> @@ -147,6 +150,14 @@ public boolean enableJetifier() { return enableJetifier; } + public void setDeps(Set dependencies) { + this.dependencies = dependencies; + } + + public Set getDeps() { + return dependencies; + } + String getSourceFileNameFrom(String prebuiltName) { if (ImmutableList.of(JAR, AAR).contains(getPackaging())) { return prebuiltName.replaceFirst("\\.(jar|aar)$", SOURCE_FILE); @@ -182,4 +193,18 @@ String getSourceFileNameFrom(String prebuiltName) { this.enableJetifier = jetifierExtension.shouldJetify(group, name, getPackaging()); this.cachePath = Paths.get(externalDependenciesExtension.getCache()); } + + public static Set filterAar(Set dependencies) { + return dependencies + .stream() + .filter(dependency -> dependency.getPackaging().equals(AAR)) + .collect(Collectors.toSet()); + } + + public static Set filterJar(Set dependencies) { + return dependencies + .stream() + .filter(dependency -> dependency.getPackaging().equals(JAR)) + .collect(Collectors.toSet()); + } } diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/manager/DependencyManager.java b/buildSrc/src/main/java/com/uber/okbuck/core/manager/DependencyManager.java index 9be802bb3..90678eb03 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/manager/DependencyManager.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/manager/DependencyManager.java @@ -4,6 +4,7 @@ import static com.uber.okbuck.core.dependency.BaseExternalDependency.JAR; import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.LinkedHashMultimap; @@ -13,6 +14,7 @@ import com.uber.okbuck.composer.common.HttpFileRuleComposer; import com.uber.okbuck.composer.java.LocalPrebuiltRuleComposer; import com.uber.okbuck.composer.java.PrebuiltRuleComposer; +import com.uber.okbuck.core.dependency.DependencyFactory; import com.uber.okbuck.core.dependency.DependencyUtils; import com.uber.okbuck.core.dependency.ExternalDependency; import com.uber.okbuck.core.dependency.LocalExternalDependency; @@ -28,14 +30,18 @@ import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ResolvedConfiguration; +import org.gradle.api.artifacts.ResolvedDependency; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,6 +54,8 @@ public class DependencyManager { private final JetifierExtension jetifierExtension; private final BuckFileManager buckFileManager; + private final Set rawDependencies = new HashSet<>(); + private final SetMultimap originalDependencyMap = LinkedHashMultimap.create(); @@ -62,6 +70,11 @@ public DependencyManager( this.buckFileManager = buckFileManager; } + public synchronized void addDependencies( + Set dependencies) { + rawDependencies.addAll(dependencies); + } + public synchronized void addDependency(ExternalDependency dependency, boolean skipPrebuilt) { VersionlessDependency versionless = dependency.getVersionless(); originalDependencyMap.put(versionless, dependency); @@ -77,7 +90,9 @@ public synchronized void addDependency(ExternalDependency dependency, boolean sk public void finalizeDependencies() { Map> filteredDependencyMap = filterDependencies(); + validateDependencies(filteredDependencyMap); + updateDependencies(filteredDependencyMap); processDependencies(filteredDependencyMap); } @@ -200,6 +215,84 @@ private void validateDependencies( } } + private void updateDependencies( + Map> dependencyMap) { + + ExternalDependenciesExtension extension = ProjectUtil.getExternalDependencyExtension(project); + // Don't create exported deps if not enabled. + if (!extension.exportedDepsEnabled()) { + return; + } + + if (!extension.versionlessEnabled()) { + throw new RuntimeException( + "Exported deps only works when resolutionAction is latest or single"); + } + + Configuration config = project.getConfigurations().create("okbuckDependencyResolver"); + config.getDependencies().addAll(rawDependencies); + + ResolvedConfiguration resolvedConfiguration = config.getResolvedConfiguration(); + + if (resolvedConfiguration.hasError()) { + // Throw failure if there was one during resolution + resolvedConfiguration.rethrowFailure(); + } + + resolvedConfiguration + .getLenientConfiguration() + .getAllModuleDependencies() + .forEach( + rDependency -> { + Set childDependencies = + childDependencies(rDependency, dependencyMap); + + if (childDependencies.size() == 0) { + return; + } + + DependencyFactory.fromDependency(rDependency) + .stream() + .filter(it -> !it.classifier().isPresent()) + .map(dependencyMap::get) + .filter(Objects::nonNull) + .map( + dependencies -> { + Preconditions.checkArgument( + dependencies.size() == 1, + "Dependency having multiple versions can't have deps: " + dependencies); + + return dependencies.stream().findAny().get(); + }) + .forEach(dependency -> dependency.setDeps(childDependencies)); + }); + } + + private static Set childDependencies( + ResolvedDependency rDependency, + Map> dependencyMap) { + return rDependency + .getChildren() + .stream() + .map( + cDependency -> + DependencyFactory.fromDependency(cDependency) + .stream() + .map(dependencyMap::get) + .filter(Objects::nonNull) + .map( + dependencies -> { + Preconditions.checkArgument( + dependencies.size() == 1, + "Child dependencies can't have multiple versions: " + dependencies); + + return dependencies.stream().findAny().get(); + }) + .collect(Collectors.toSet())) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + private void processDependencies( Map> dependencyMap) { Path rootPath = project.getRootDir().toPath(); diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/model/android/ExoPackageScope.java b/buildSrc/src/main/java/com/uber/okbuck/core/model/android/ExoPackageScope.java index cb155521a..b0c1c99ec 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/model/android/ExoPackageScope.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/model/android/ExoPackageScope.java @@ -105,7 +105,7 @@ private void extractDependencies(Scope base, List exoPackageDependencies } Optional externalDepOptional = - base.getAllExternal() + base.getExternalDeps(false) .stream() .filter( dependency -> { @@ -119,10 +119,10 @@ private void extractDependencies(Scope base, List exoPackageDependencies .findFirst(); if (externalDepOptional.isPresent()) { - getAllExternal().add(externalDepOptional.get()); + this.external.add(externalDepOptional.get()); } else { Optional variantDepOptional = - base.getTargetDeps() + base.getTargetDeps(false) .stream() .filter( variant -> { @@ -135,7 +135,7 @@ private void extractDependencies(Scope base, List exoPackageDependencies }) .findFirst(); - variantDepOptional.ifPresent(target -> getTargetDeps().add(target)); + variantDepOptional.ifPresent(targetDeps::add); } }); } diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/model/base/Scope.java b/buildSrc/src/main/java/com/uber/okbuck/core/model/base/Scope.java index 9cec7376c..0d95ea5ce 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/model/base/Scope.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/model/base/Scope.java @@ -1,8 +1,5 @@ package com.uber.okbuck.core.model.base; -import static com.uber.okbuck.core.dependency.BaseExternalDependency.AAR; -import static com.uber.okbuck.core.dependency.BaseExternalDependency.JAR; - import com.android.build.api.attributes.VariantAttr; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -23,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -38,6 +36,7 @@ import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.DependencySet; +import org.gradle.api.artifacts.ProjectDependency; import org.gradle.api.artifacts.component.ComponentIdentifier; import org.gradle.api.artifacts.component.ModuleComponentIdentifier; import org.gradle.api.artifacts.component.ProjectComponentIdentifier; @@ -47,8 +46,6 @@ public class Scope { - private static final String EMPTY_GROUP = "----empty----"; - private final Set javaResources; private final Set sources; @Nullable private final Configuration configuration; @@ -56,8 +53,8 @@ public class Scope { private final Map> customOptions; protected final Project project; - private final Set targetDeps = new HashSet<>(); - private final Set external = new HashSet<>(); + protected final Set targetDeps = new HashSet<>(); + protected final Set external = new HashSet<>(); @Nullable private Set annotationProcessors; @@ -73,10 +70,6 @@ public Map> getCustomOptions() { return customOptions; } - public final Set getAllExternal() { - return external; - } - /** Used to filter out only project dependencies when resolving a configuration. */ private static final Spec PROJECT_FILTER = componentIdentifier -> componentIdentifier instanceof ProjectComponentIdentifier; @@ -120,26 +113,71 @@ protected Scope( ProjectUtil.getDependencyCache(project)); } - public final Set getTargetDeps() { - return targetDeps; + public Set getTargetDeps(boolean firstLevel) { + ExternalDependenciesExtension okBuckExtension = + ProjectUtil.getExternalDependencyExtension(project); + + if (configuration != null && firstLevel) { + Set firstLevelProjects = + configuration + .getAllDependencies() + .withType(ProjectDependency.class) + .stream() + .map(dependency -> dependency.getDependencyProject().getPath()) + .collect(Collectors.toSet()); + + return targetDeps + .stream() + .filter(target -> firstLevelProjects.contains(target.getProject().getPath())) + .collect(Collectors.toSet()); + } else { + return targetDeps; + } } - public Set getExternalDeps() { - return getAllExternal().stream().map(depCache::get).collect(Collectors.toSet()); + public final Set getTargetDeps() { + ExternalDependenciesExtension externalDependenciesExtension = + ProjectUtil.getExternalDependencyExtension(project); + + return getTargetDeps(externalDependenciesExtension.exportedDepsEnabled()); } - public Set getExternalJarDeps() { - return getExternalDeps() - .stream() - .filter(dependency -> dependency.getPackaging().equals(JAR)) - .collect(Collectors.toSet()); + public Set getExternalDeps(boolean firstLevel) { + if (configuration != null && firstLevel) { + Set firstLevelDependencies = + configuration + .getAllDependencies() + .withType(org.gradle.api.artifacts.ExternalDependency.class) + .stream() + .map(DependencyFactory::fromDependency) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + return external + .stream() + .map(depCache::get) + .filter( + dependency -> { + VersionlessDependency vDependency = dependency.getVersionless(); + + // Always include local dependencies + if (vDependency.group().equals(DependencyFactory.LOCAL_GROUP)) { + return true; + } + return firstLevelDependencies.contains(vDependency); + }) + .collect(Collectors.toSet()); + } else { + return external.stream().map(depCache::get).collect(Collectors.toSet()); + } } - public Set getExternalAarDeps() { - return getExternalDeps() - .stream() - .filter(dependency -> dependency.getPackaging().equals(AAR)) - .collect(Collectors.toSet()); + public final Set getExternalDeps() { + OkBuckExtension okBuckExtension = ProjectUtil.getOkBuckExtension(project); + ExternalDependenciesExtension externalDependenciesExtension = + okBuckExtension.getExternalDependenciesExtension(); + + return getExternalDeps(externalDependenciesExtension.exportedDepsEnabled()); } /** @@ -153,41 +191,14 @@ public Set getAnnotationProcessors() { } if (annotationProcessors == null) { - Set firstLevelDependencies = - configuration - .getAllDependencies() - .stream() - .map( - dependency -> { - String group = - dependency.getGroup() == null ? EMPTY_GROUP : dependency.getGroup(); - return VersionlessDependency.builder() - .setGroup(group) - .setName(dependency.getName()) - .build(); - }) - .collect(Collectors.toSet()); - annotationProcessors = Streams.concat( - getExternalDeps() + getExternalDeps(true) .stream() - .filter( - dependency -> - firstLevelDependencies.contains(dependency.getVersionless())) .map(depCache::getAnnotationProcessors) .flatMap(Set::stream), - targetDeps + getTargetDeps(true) .stream() - .filter( - target -> { - VersionlessDependency versionless = - VersionlessDependency.builder() - .setGroup((String) target.getProject().getGroup()) - .setName(target.getProject().getName()) - .build(); - return firstLevelDependencies.contains(versionless); - }) .map( target -> { OkBuckExtension okBuckExtension = target.getOkbuck(); @@ -298,6 +309,8 @@ private static ImmutableSet getArtifacts( } private void extractConfiguration(Configuration configuration) { + depCache.addDependencies(configuration.getAllDependencies()); + Set jarArtifacts = getArtifacts(configuration, PROJECT_FILTER, ImmutableList.of("jar")); diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/model/jvm/JvmTarget.java b/buildSrc/src/main/java/com/uber/okbuck/core/model/jvm/JvmTarget.java index 4276368fd..d19535986 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/model/jvm/JvmTarget.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/model/jvm/JvmTarget.java @@ -1,11 +1,15 @@ package com.uber.okbuck.core.model.jvm; +import static com.uber.okbuck.core.dependency.ExternalDependency.filterAar; +import static com.uber.okbuck.core.dependency.ExternalDependency.filterJar; + import com.android.builder.model.LintOptions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.errorprone.annotations.Var; import com.uber.okbuck.OkBuckGradlePlugin; import com.uber.okbuck.composer.jvm.JvmBuckRuleComposer; import com.uber.okbuck.core.annotation.AnnotationProcessorCache; @@ -18,7 +22,9 @@ import com.uber.okbuck.core.model.base.Scope; import com.uber.okbuck.core.model.base.Target; import com.uber.okbuck.core.util.ProjectUtil; +import com.uber.okbuck.extension.ExternalDependenciesExtension; import java.io.File; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; @@ -162,8 +168,7 @@ public Scope getTestProvided() { /** api external deps */ public Set getApiExternalDeps() { - Configuration apiConfiguration = - DependencyUtils.getConfiguration(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, getProject()); + Configuration apiConfiguration = getApiConfiguration(); if (apiConfiguration != null) { Set versionlessApiDependencies = @@ -172,6 +177,7 @@ public Set getApiExternalDeps() { .withType(org.gradle.api.artifacts.ExternalDependency.class) .stream() .map(DependencyFactory::fromDependency) + .flatMap(Collection::stream) .collect(Collectors.toSet()); return getMain() @@ -186,8 +192,7 @@ public Set getApiExternalDeps() { /** api target deps */ public Set getApiTargetDeps() { - Configuration apiConfiguration = - DependencyUtils.getConfiguration(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, getProject()); + Configuration apiConfiguration = getApiConfiguration(); if (apiConfiguration != null) { Set projectApiDependencies = @@ -208,6 +213,28 @@ public Set getApiTargetDeps() { } } + @Nullable + private Configuration getApiConfiguration() { + ExternalDependenciesExtension extension = + ProjectUtil.getExternalDependencyExtension(getProject()); + + if (extension.exportedDepsEnabled()) { + @Var + Configuration apiConfiguration = + DependencyUtils.getConfiguration( + JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, getProject()); + + if (apiConfiguration == null) { + apiConfiguration = + DependencyUtils.getConfiguration(JavaPlugin.API_CONFIGURATION_NAME, getProject()); + } + + return apiConfiguration; + } else { + return null; + } + } + /** Lint Scope */ public Scope getLint() { LintManager manager = ProjectUtil.getLintManager(getProject()); @@ -549,6 +576,10 @@ public Set getExternalDeps(boolean test) { } } + public Set getExternalAarDeps(boolean test) { + return filterAar(getExternalDeps(test)); + } + /** * Get api target deps. exportedDeps = api * @@ -562,6 +593,10 @@ public Set getExternalExportedDeps(boolean test) { } } + public Set getExternalExportedAarDeps(boolean test) { + return filterAar(getExternalExportedDeps(test)); + } + /** * Get apt target deps. exportedDeps = apt * @@ -569,9 +604,9 @@ public Set getExternalExportedDeps(boolean test) { */ public Set getExternalAptDeps(boolean test) { if (test) { - return getTestApt().getExternalJarDeps(); + return filterJar(getTestApt().getExternalDeps()); } else { - return getApt().getExternalJarDeps(); + return filterJar(getApt().getExternalDeps()); } } diff --git a/buildSrc/src/main/java/com/uber/okbuck/core/util/ProjectUtil.java b/buildSrc/src/main/java/com/uber/okbuck/core/util/ProjectUtil.java index 81ea6e7c0..3863ebc11 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/core/util/ProjectUtil.java +++ b/buildSrc/src/main/java/com/uber/okbuck/core/util/ProjectUtil.java @@ -17,6 +17,7 @@ import com.uber.okbuck.core.manager.ScalaManager; import com.uber.okbuck.core.manager.TransformManager; import com.uber.okbuck.core.model.base.ProjectType; +import com.uber.okbuck.extension.ExternalDependenciesExtension; import com.uber.okbuck.extension.OkBuckExtension; import java.io.File; import java.util.HashMap; @@ -105,6 +106,13 @@ public static OkBuckExtension getOkBuckExtension(Project project) { project.getRootProject().getExtensions().getByName(OkBuckGradlePlugin.OKBUCK); } + public static ExternalDependenciesExtension getExternalDependencyExtension(Project project) { + OkBuckExtension okBuckExtension = + (OkBuckExtension) + project.getRootProject().getExtensions().getByName(OkBuckGradlePlugin.OKBUCK); + return okBuckExtension.getExternalDependenciesExtension(); + } + @Nullable public static String findVersionInClasspath(Project project, String group, String module) { return project diff --git a/buildSrc/src/main/java/com/uber/okbuck/extension/ExternalDependenciesExtension.java b/buildSrc/src/main/java/com/uber/okbuck/extension/ExternalDependenciesExtension.java index 2aea3f3c9..8990c0288 100644 --- a/buildSrc/src/main/java/com/uber/okbuck/extension/ExternalDependenciesExtension.java +++ b/buildSrc/src/main/java/com/uber/okbuck/extension/ExternalDependenciesExtension.java @@ -18,6 +18,9 @@ public class ExternalDependenciesExtension { /** Specifies what resolution action to use for external dependencies. */ @Input private ResolutionAction resolutionAction = ResolutionAction.ALL; + /** Specifies whether to enable exported_deps for external dependencies or not. */ + @Input private boolean enableExportedDeps = false; + /** * Stores the dependencies which are allowed to have more than 1 version. This is needed for few * dependencies like robolectric runtime deps. @@ -83,4 +86,8 @@ public String getCache() { public boolean shouldDownloadInBuck() { return downloadInBuck; } + + public boolean exportedDepsEnabled() { + return enableExportedDeps; + } } diff --git a/buildSrc/src/main/rocker/com/uber/okbuck/template/android/ResourceRule.rocker.raw b/buildSrc/src/main/rocker/com/uber/okbuck/template/android/ResourceRule.rocker.raw index 00fb73380..25b3d0612 100644 --- a/buildSrc/src/main/rocker/com/uber/okbuck/template/android/ResourceRule.rocker.raw +++ b/buildSrc/src/main/rocker/com/uber/okbuck/template/android/ResourceRule.rocker.raw @@ -4,6 +4,7 @@ String pkg, Collection res, String projectRes, Collection assets, +Collection exportedDeps, boolean resourceUnion) @com.uber.okbuck.template.base.BuckRule.template() -> { package = '@pkg', @@ -24,6 +25,13 @@ boolean resourceUnion) } ]), } +@if (valid(exportedDeps)) { + exported_deps = [ + @for (dep : sorted(exportedDeps)) { + '@dep', + } + ], +} @if (resourceUnion) { resource_union = True, } diff --git a/buildSrc/src/main/rocker/com/uber/okbuck/template/config/OkbuckPrebuilt.rocker.raw b/buildSrc/src/main/rocker/com/uber/okbuck/template/config/OkbuckPrebuilt.rocker.raw index 2c0277a1a..226748407 100644 --- a/buildSrc/src/main/rocker/com/uber/okbuck/template/config/OkbuckPrebuilt.rocker.raw +++ b/buildSrc/src/main/rocker/com/uber/okbuck/template/config/OkbuckPrebuilt.rocker.raw @@ -8,12 +8,16 @@ def okbuck_prebuilt( maven_coords, sha256, sources_sha256=None, + deps=None, visibility=None, enable_jetifier=False, ): if visibility == None: visibility = ['PUBLIC'] + if deps == None: + deps = [] + prebuilt_type = maven_coords.split(':')[2] if sources_sha256 != None: @@ -49,6 +53,7 @@ def okbuck_prebuilt( aar = ':' + prebuilt_file_name, source_jar = ':' + prebuilt_sources_file_name if sources_maven_coords != None else None, maven_coords = maven_coords, + deps = deps, visibility = visibility, enable_jetifier = enable_jetifier, ) @@ -58,6 +63,7 @@ def okbuck_prebuilt( binary_jar = ':' + prebuilt_file_name, source_jar = ':' + prebuilt_sources_file_name if sources_maven_coords != None else None, maven_coords = maven_coords, + deps = deps, visibility = visibility, enable_jetifier = enable_jetifier, ) diff --git a/buildSrc/src/main/rocker/com/uber/okbuck/template/java/Prebuilt.rocker.raw b/buildSrc/src/main/rocker/com/uber/okbuck/template/java/Prebuilt.rocker.raw index a93054351..eb789bc9b 100644 --- a/buildSrc/src/main/rocker/com/uber/okbuck/template/java/Prebuilt.rocker.raw +++ b/buildSrc/src/main/rocker/com/uber/okbuck/template/java/Prebuilt.rocker.raw @@ -12,6 +12,13 @@ boolean enableJetifier, @if (valid(sourcesSha256)) { sources_sha256 = '@sourcesSha256', } +@if (valid(deps)) { + deps = [ + @for (dep : sorted(deps)) { + '@dep', + } + ], +} @if (enableJetifier) { enable_jetifier = True, } diff --git a/dependencies.gradle b/dependencies.gradle index 7f766d52a..f876aabdb 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -71,6 +71,7 @@ def external = [ avroIpc : "org.apache.avro:avro-ipc:1.7.7", avroIpcTests : "org.apache.avro:avro-ipc:1.7.7:tests", saxon : "net.sf.saxon:Saxon-HE:9.7.0-15", + scalaLibrary : "org.scala-lang:scala-library:2.12.4" ] def lint = [ @@ -98,10 +99,11 @@ def test = [ kotlinTest : "org.jetbrains.kotlin:kotlin-test-junit:${versions.kotlin}", mockito : "org.mockito:mockito-core:2.15.0", robolectric : "org.robolectric:robolectric:3.8", + scalaTest : "org.scalatest:scalatest_2.12:3.0.5" ] ext.config = [ - "build": buildConfig, + "build": buildConfig, ] ext.deps = [ @@ -111,5 +113,5 @@ ext.deps = [ "external": external, "lint" : lint, "test" : test, - "versions": versions + "versions": versions, ] diff --git a/libraries/parcelable/build.gradle b/libraries/parcelable/build.gradle index ee20a4e9b..4a2964258 100644 --- a/libraries/parcelable/build.gradle +++ b/libraries/parcelable/build.gradle @@ -5,3 +5,7 @@ android { consumerProguardFiles "proguard.txt" } } + +dependencies { + api deps.androidx.material +} diff --git a/libraries/scalalibrary/build.gradle b/libraries/scalalibrary/build.gradle index f13f1ef7c..2ee74d5ce 100644 --- a/libraries/scalalibrary/build.gradle +++ b/libraries/scalalibrary/build.gradle @@ -4,10 +4,10 @@ plugins { } dependencies { - compile "org.scala-lang:scala-library:2.12.4" + compile deps.external.scalaLibrary - testCompile "org.scalatest:scalatest_2.12:3.0.5" - testCompile "junit:junit:4.12" + testCompile deps.test.scalaTest + testCompile deps.test.junit } mainClassName = "com.uber.okbuck.scala.example.Hello"