diff options
author | Xavier Ducrohet <xav@android.com> | 2012-10-05 10:56:03 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2012-10-05 17:59:45 -0700 |
commit | dc71ab2627ac4f4f8843dd0d5a1d84ac0f04662d (patch) | |
tree | 77c79f6230302df67176b79f4d616a1c3e9f449b /gradle/src | |
parent | d14ea2c706561925d45feb30a1b57732bcefc383 (diff) | |
download | build-dc71ab2627ac4f4f8843dd0d5a1d84ac0f04662d.tar.gz |
Support compile config for flavors and build types.
Read dependency graph and create list of JarDependency
and AndroidDependency for each configuration.
Set Jars and AndroidDependency on each VariantConfig
object.
Add a AndroidDependency report task (called androidDependency)
The prepareDependenciesTask will prepare the same artifact
multiple time if it's used by different variants and they
are all built. This will be fixed in the next patch.
Change-Id: I4f11565c3629a54f022ecc82f81d4900ef2bd0c9
Diffstat (limited to 'gradle/src')
12 files changed, 513 insertions, 71 deletions
diff --git a/gradle/src/main/groovy/com/android/build/gradle/AndroidDependencyTask.groovy b/gradle/src/main/groovy/com/android/build/gradle/AndroidDependencyTask.groovy new file mode 100644 index 0000000..882572c --- /dev/null +++ b/gradle/src/main/groovy/com/android/build/gradle/AndroidDependencyTask.groovy @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.android.build.gradle + +import com.android.build.gradle.internal.ApplicationVariant + +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.Configuration +import org.gradle.api.tasks.TaskAction +import org.gradle.logging.StyledTextOutputFactory +import com.android.build.gradle.internal.AndroidAsciiReportRenderer + +/** + */ +class AndroidDependencyTask extends DefaultTask { + + private AndroidAsciiReportRenderer renderer = new AndroidAsciiReportRenderer(); + + private Set<ApplicationVariant> variants = []; + + @TaskAction + public void generate() throws IOException { + renderer.setOutput(getServices().get(StyledTextOutputFactory.class).create(getClass())); + + SortedSet<ApplicationVariant> sortedConfigurations = new TreeSet<Configuration>( + new Comparator<ApplicationVariant>() { + public int compare(ApplicationVariant conf1, ApplicationVariant conf2) { + return conf1.getName().compareTo(conf2.getName()); + } + }); + sortedConfigurations.addAll(getVariants()); + for (ApplicationVariant variant : sortedConfigurations) { + renderer.startVariant(variant); + renderer.render(variant); + } + } + + /** + * Returns the configurations to generate the report for. Default to all configurations of + * this task's containing project. + * + * @return the configurations. + */ + public Set<ApplicationVariant> getVariants() { + return variants; + } + + /** + * Sets the configurations to generate the report for. + * + * @param configurations The configuration. Must not be null. + */ + public void setVariants(Collection<ApplicationVariant> variants) { + this.variants.addAll(variants); + } +} diff --git a/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy index 3d49b75..068c86d 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy @@ -17,11 +17,14 @@ package com.android.build.gradle import com.android.build.gradle.internal.BuildTypeData import com.android.build.gradle.internal.BuildTypeDsl +import com.android.build.gradle.internal.ConfigurationDependencies import com.android.build.gradle.internal.ProductFlavorData import com.android.build.gradle.internal.ProductFlavorDsl import com.android.build.gradle.internal.ProductionAppVariant import com.android.build.gradle.internal.TestAppVariant +import com.android.builder.AndroidDependency import com.android.builder.BuildType +import com.android.builder.JarDependency import com.android.builder.VariantConfiguration import com.google.common.collect.ArrayListMultimap import com.google.common.collect.ListMultimap @@ -106,6 +109,13 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl } private void createAndroidTasks() { + // resolve dependencies for all config + List<ConfigurationDependencies> dependencies = [] + dependencies.addAll(buildTypes.values()) + dependencies.addAll(productFlavors.values()) + resolveDependencies(dependencies) + + // now create the tasks. if (productFlavors.isEmpty()) { createTasksForDefaultBuild() } else { @@ -142,6 +152,8 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl createTasksForMultiFlavoredBuilds(array, 0, map) } } + + createDependencyReportTask() } private createTasksForMultiFlavoredBuilds(ProductFlavorData[] datas, int i, @@ -177,13 +189,32 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl ProductFlavorData defaultConfigData = getDefaultConfigData(); for (BuildTypeData buildTypeData : buildTypes.values()) { + List<ConfigurationDependencies> configDependencies = [] + configDependencies.add(defaultConfigData) + configDependencies.add(buildTypeData) + + // list of dependency to set on the variantConfig + List<JarDependency> jars = [] + jars.addAll(defaultConfigData.jars) + jars.addAll(buildTypeData.jars) + + // the order of the libraries is important. In descending order: + // build types, flavors, defaultConfig. + List<AndroidDependency> libs = [] + libs.addAll(buildTypeData.libraries) + // no flavors, just add the default config + libs.addAll(defaultConfigData.libraries) def variantConfig = new VariantConfiguration( defaultConfigData.productFlavor, defaultConfigData.sourceSet, buildTypeData.buildType, buildTypeData.sourceSet) + variantConfig.setJarDependencies(jars) + variantConfig.setAndroidDependencies(libs) + ProductionAppVariant productionAppVariant = addVariant(variantConfig, - buildTypeData.assembleTask) + buildTypeData.assembleTask, configDependencies) + variants.add(productionAppVariant) if (buildTypeData == testData) { testedVariant = productionAppVariant @@ -197,11 +228,21 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl testData.buildType, null, VariantConfiguration.Type.TEST, testedVariant.config) - // TODO: add actual dependencies - testVariantConfig.setAndroidDependencies(null) + List<ConfigurationDependencies> testConfigDependencies = [] + testConfigDependencies.add(defaultConfigData.testConfigDependencies) + + // list of dependency to set on the variantConfig + List<JarDependency> testJars = [] + testJars.addAll(defaultConfigData.testConfigDependencies.jars) + List<AndroidDependency> testLibs = [] + testLibs.addAll(defaultConfigData.testConfigDependencies.libraries) + + testVariantConfig.setJarDependencies(testJars) + testVariantConfig.setAndroidDependencies(testLibs) def testVariant = new TestAppVariant(testVariantConfig) - createTestTasks(testVariant, testedVariant) + variants.add(testVariant) + createTestTasks(testVariant, testedVariant, testConfigDependencies) } /** @@ -222,6 +263,19 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl def assembleTask for (BuildTypeData buildTypeData : buildTypes.values()) { + List<ConfigurationDependencies> configDependencies = [] + configDependencies.add(defaultConfigData) + configDependencies.add(buildTypeData) + + // list of dependency to set on the variantConfig + List<JarDependency> jars = [] + jars.addAll(defaultConfigData.jars) + jars.addAll(buildTypeData.jars) + + // the order of the libraries is important. In descending order: + // build types, flavors, defaultConfig. + List<AndroidDependency> libs = [] + libs.addAll(buildTypeData.libraries) def variantConfig = new VariantConfiguration( extension.defaultConfig, getDefaultConfigData().sourceSet, @@ -229,9 +283,20 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl for (ProductFlavorData data : flavorDataList) { variantConfig.addProductFlavor(data.productFlavor, data.sourceSet) + jars.addAll(data.jars) + libs.addAll(data.libraries) + configDependencies.add(data) } - ProductionAppVariant productionAppVariant = addVariant(variantConfig, null) + // now add the defaultConfig + libs.addAll(defaultConfigData.libraries) + + variantConfig.setJarDependencies(jars) + variantConfig.setAndroidDependencies(libs) + + ProductionAppVariant productionAppVariant = addVariant(variantConfig, null, + configDependencies) + variants.add(productionAppVariant) buildTypeData.assembleTask.dependsOn productionAppVariant.assembleTask @@ -254,15 +319,32 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl testData.buildType, null, VariantConfiguration.Type.TEST, testedVariant.config) + List<ConfigurationDependencies> testConfigDependencies = [] + testConfigDependencies.add(defaultConfigData.testConfigDependencies) + + // list of dependency to set on the variantConfig + List<JarDependency> testJars = [] + testJars.addAll(defaultConfigData.testConfigDependencies.jars) + + // the order of the libraries is important. In descending order: + // flavors, defaultConfig. + List<AndroidDependency> testLibs = [] + for (ProductFlavorData data : flavorDataList) { testVariantConfig.addProductFlavor(data.productFlavor, data.testSourceSet) + testJars.addAll(data.testConfigDependencies.jars) + testLibs.addAll(data.testConfigDependencies.libraries) } - // TODO: add actual dependencies - testVariantConfig.setAndroidDependencies(null) + // now add the default config + testLibs.addAll(defaultConfigData.testConfigDependencies.libraries) + + testVariantConfig.setJarDependencies(testJars) + testVariantConfig.setAndroidDependencies(testLibs) def testVariant = new TestAppVariant(testVariantConfig) - createTestTasks(testVariant, testedVariant) + variants.add(testVariant) + createTestTasks(testVariant, testedVariant, testConfigDependencies) } private Task createAssembleTask(ProductFlavorData[] flavorDataList) { @@ -281,11 +363,12 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl * @param assembleTask an optional assembleTask to be used. If null, a new one is created. * @return */ - private ProductionAppVariant addVariant(VariantConfiguration variantConfig, Task assembleTask) { + private ProductionAppVariant addVariant(VariantConfiguration variantConfig, Task assembleTask, + List<ConfigurationDependencies> configDependencies) { def variant = new ProductionAppVariant(variantConfig) - def prepareDependenciesTask = createPrepareDependenciesTask(variant) + def prepareDependenciesTask = createPrepareDependenciesTask(variant, configDependencies) // Add a task to process the manifest(s) def processManifestTask = createProcessManifestTask(variant, "manifests") diff --git a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy index a07766b..954d5dd 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy @@ -18,6 +18,7 @@ package com.android.build.gradle import com.android.SdkConstants import com.android.build.gradle.internal.AndroidDependencyImpl import com.android.build.gradle.internal.ApplicationVariant +import com.android.build.gradle.internal.ConfigurationDependencies import com.android.build.gradle.internal.ProductFlavorData import com.android.build.gradle.internal.ProductionAppVariant import com.android.build.gradle.internal.TestAppVariant @@ -57,6 +58,8 @@ abstract class BasePlugin { private final Map<Object, AndroidBuilder> builders = [:] + final List<ApplicationVariant> variants = [] + protected Project project protected File sdkDir private DefaultSdkParser androidSdkParser @@ -370,9 +373,15 @@ abstract class BasePlugin { variant.compileTask = compileTask } - protected void createTestTasks(TestAppVariant variant, ProductionAppVariant testedVariant) { + protected void createTestTasks(TestAppVariant variant, ProductionAppVariant testedVariant, + List<ConfigurationDependencies> configDependencies) { + + def prepareDependenciesTask = createPrepareDependenciesTask(variant, configDependencies) + // Add a task to process the manifest def processManifestTask = createProcessManifestTask(variant, "manifests") + // TODO - move this + processManifestTask.dependsOn prepareDependenciesTask // Add a task to crunch resource files def crunchTask = createCrunchResTask(variant) @@ -395,6 +404,8 @@ abstract class BasePlugin { createProcessJavaResTask(variant) def compileAidl = createAidlTask(variant) + // TODO - move this + compileAidl.dependsOn prepareDependenciesTask // Add a task to compile the test application createCompileTask(variant, testedVariant, processResources, generateBuildConfigTask, @@ -521,41 +532,82 @@ abstract class BasePlugin { uninstallAll.dependsOn uninstallTask } - PrepareDependenciesTask createPrepareDependenciesTask(ProductionAppVariant variant) { - // TODO - include variant specific dependencies too - def compileClasspath = project.configurations.compile - - // TODO - shouldn't need to do this - fix this in Gradle - ensureConfigured(compileClasspath) + protected void createDependencyReportTask() { + def androidDependencyTask = project.tasks.add("androidDependencies", AndroidDependencyTask) + androidDependencyTask.setDescription("Displays the Android dependencies of the project") + androidDependencyTask.setVariants(variants) + androidDependencyTask.setGroup("Help") + } + PrepareDependenciesTask createPrepareDependenciesTask(ApplicationVariant variant, + List<ConfigurationDependencies> configDependenciesList) { def prepareDependenciesTask = project.tasks.add("prepare${variant.name}Dependencies", PrepareDependenciesTask) prepareDependenciesTask.plugin = this prepareDependenciesTask.variant = variant - // TODO - should be able to infer this - prepareDependenciesTask.dependsOn compileClasspath + // look at all the flavors/build types of the variant and get all the libraries + // to make sure they are unarchived before the build runs. + for (ConfigurationDependencies configDependencies : configDependenciesList) { + prepareDependenciesTask.dependsOn configDependencies.configuration.buildDependencies + for (AndroidDependencyImpl lib : configDependencies.libraries) { + addDependencyToPrepareTask(prepareDependenciesTask, lib) + prepareDependenciesTask.add(lib.bundle, lib.bundleFolder) + } + } + + return prepareDependenciesTask + } + + def resolveDependencies(List<ConfigurationDependencies> configs) { + // start with the default config and its test + resolveDependencyForConfig(defaultConfigData) + resolveDependencyForConfig(defaultConfigData.testConfigDependencies) + + // and then loop on all the other configs + for (ConfigurationDependencies config : configs) { + resolveDependencyForConfig(config) + if (config.testConfigDependencies != null) { + resolveDependencyForConfig(config.testConfigDependencies) + } + } + } + + def resolveDependencyForConfig( + ConfigurationDependencies configDependencies) { + + def compileClasspath = configDependencies.configuration + + // TODO - shouldn't need to do this - fix this in Gradle + ensureConfigured(compileClasspath) - def checker = new DependencyChecker(variant, logger) + def checker = new DependencyChecker(logger) - // TODO - defer downloading until required - // TODO - build the library dependency graph + // TODO - defer downloading until required -- This is hard to do as we need the info to build the variant config. List<AndroidDependency> bundles = [] List<JarDependency> jars = [] Map<ModuleVersionIdentifier, List<AndroidDependency>> modules = [:] Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts = [:] collectArtifacts(compileClasspath, artifacts) compileClasspath.resolvedConfiguration.resolutionResult.root.dependencies.each { ResolvedDependencyResult dep -> - addDependency(dep.selected, prepareDependenciesTask, checker, - bundles, jars, modules, artifacts) + addDependency(dep.selected, checker, bundles, jars, modules, artifacts) } - variant.config.androidDependencies = bundles - variant.config.jarDependencies = jars + configDependencies.libraries = bundles + configDependencies.jars = jars // TODO - filter bundles out of source set classpath - return prepareDependenciesTask + configureBuild(configDependencies) + } + + def addDependencyToPrepareTask(PrepareDependenciesTask prepareDependenciesTask, + AndroidDependencyImpl lib) { + prepareDependenciesTask.add(lib.bundle, lib.bundleFolder) + + for (AndroidDependencyImpl childLib : lib.dependencies) { + addDependencyToPrepareTask(prepareDependenciesTask, childLib) + } } def ensureConfigured(Configuration config) { @@ -579,7 +631,6 @@ abstract class BasePlugin { } def addDependency(ResolvedModuleVersionResult moduleVersion, - PrepareDependenciesTask prepareDependenciesTask, DependencyChecker checker, Collection<AndroidDependency> bundles, Collection<JarDependency> jars, @@ -597,7 +648,7 @@ abstract class BasePlugin { def nestedBundles = [] moduleVersion.dependencies.each { ResolvedDependencyResult dep -> - addDependency(dep.selected, prepareDependenciesTask, checker, nestedBundles, + addDependency(dep.selected, checker, nestedBundles, jars, modules, artifacts) } @@ -606,8 +657,9 @@ abstract class BasePlugin { if (artifact.type == 'alb') { def explodedDir = project.file( "$project.buildDir/exploded-bundles/$artifact.file.name") - bundlesForThisModule << new AndroidDependencyImpl(explodedDir, nestedBundles) - prepareDependenciesTask.add(artifact.file, explodedDir) + bundlesForThisModule << new AndroidDependencyImpl( + id.group + ":" + id.name + ":" + id.version, + explodedDir, nestedBundles, artifact.file) } else { // TODO - need the correct values for the boolean flags jars << new JarDependency(artifact.file.absolutePath, true, true, true) @@ -621,5 +673,36 @@ abstract class BasePlugin { bundles.addAll(bundlesForThisModule) } + + private void configureBuild(ConfigurationDependencies configurationDependencies) { + def configuration = configurationDependencies.configuration + + addDependsOnTaskInOtherProjects( + project.getTasks().getByName(JavaBasePlugin.BUILD_NEEDED_TASK_NAME), true, + JavaBasePlugin.BUILD_NEEDED_TASK_NAME, configuration); + addDependsOnTaskInOtherProjects( + project.getTasks().getByName(JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME), false, + JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME, configuration); + } + + /** + * Adds a dependency on tasks with the specified name in other projects. The other projects + * are determined from project lib dependencies using the specified configuration name. + * These may be projects this project depends on or projects that depend on this project + * based on the useDependOn argument. + * + * @param task Task to add dependencies to + * @param useDependedOn if true, add tasks from projects this project depends on, otherwise + * use projects that depend on this one. + * @param otherProjectTaskName name of task in other projects + * @param configurationName name of configuration to use to find the other projects + */ + private void addDependsOnTaskInOtherProjects(final Task task, boolean useDependedOn, + String otherProjectTaskName, + Configuration configuration) { + Project project = task.getProject(); + task.dependsOn(configuration.getTaskDependencyFromProjectDependency( + useDependedOn, otherProjectTaskName)); + } } diff --git a/gradle/src/main/groovy/com/android/build/gradle/DependencyChecker.groovy b/gradle/src/main/groovy/com/android/build/gradle/DependencyChecker.groovy index f727999..a9ca472 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/DependencyChecker.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/DependencyChecker.groovy @@ -15,7 +15,6 @@ */ package com.android.build.gradle -import com.android.build.gradle.internal.ApplicationVariant import com.android.utils.ILogger import org.gradle.api.artifacts.ModuleVersionIdentifier @@ -24,25 +23,18 @@ import org.gradle.api.artifacts.ModuleVersionIdentifier */ class DependencyChecker { - final ApplicationVariant variant final logger - final int minSdkVersion + final List<Integer> mFoundAndroidApis = [] + final List<String> mFoundBouncyCastle = [] - DependencyChecker(ApplicationVariant variant, ILogger logger) { - this.variant = variant + DependencyChecker(ILogger logger) { this.logger = logger; - this.minSdkVersion = variant.config.getMinSdkVersion() } - private boolean excluded(ModuleVersionIdentifier id) { + boolean excluded(ModuleVersionIdentifier id) { if (id.group == 'com.google.android' && id.name == 'android') { int moduleLevel = getApiLevelFromMavenArtifact(id.version) - - if (minSdkVersion < moduleLevel) { - throw new RuntimeException(String.format( - "ERROR: Android API level %d is in the dependency graph, but minSdkVersion for '%s' is %d", - moduleLevel, variant.name, minSdkVersion)) - } + mFoundAndroidApis.add(moduleLevel) logger.info("Ignoring Android API artifact: " + id) return true @@ -77,16 +69,7 @@ class DependencyChecker { } if (id.group == 'org.bouncycastle' && id.name.startsWith("bcprov")) { - if (minSdkVersion >= 11) { - // this is when the version of BouncyCastle inside Android was jarjar'ed so this - // is fine - return false; - } - - // TODO check which version of BC is used by the platform and the app. - throw new RuntimeException(String.format( - "ERROR: Dependency %s is conflicting with the internal version provided by Android. To use, please repackage with jarjar to change the class packages", - id)) + mFoundBouncyCastle.add(id.version) } return false diff --git a/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy index 5f256a2..8c57944 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy @@ -16,12 +16,14 @@ package com.android.build.gradle import com.android.build.gradle.internal.BuildTypeData +import com.android.build.gradle.internal.ConfigurationDependencies import com.android.build.gradle.internal.ProductFlavorData import com.android.build.gradle.internal.ProductionAppVariant import com.android.build.gradle.internal.TestAppVariant import com.android.builder.AndroidDependency import com.android.builder.BuildType import com.android.builder.BundleDependency +import com.android.builder.JarDependency import com.android.builder.VariantConfiguration import org.gradle.api.Plugin import org.gradle.api.Project @@ -81,22 +83,48 @@ class LibraryPlugin extends BasePlugin implements Plugin<Project> { } void createAndroidTasks() { + // resolve dependencies for all config + List<ConfigurationDependencies> dependencies = [] + dependencies.add(debugBuildTypeData) + dependencies.add(releaseBuildTypeData) + resolveDependencies(dependencies) + ProductionAppVariant testedVariant = createLibraryTasks(debugBuildTypeData) createLibraryTasks(releaseBuildTypeData) createTestTasks(testedVariant) + createDependencyReportTask() } ProductionAppVariant createLibraryTasks(BuildTypeData buildTypeData) { ProductFlavorData defaultConfigData = getDefaultConfigData(); + List<ConfigurationDependencies> configDependencies = [] + configDependencies.add(defaultConfigData) + configDependencies.add(buildTypeData) + + // list of dependency to set on the variantConfig + List<JarDependency> jars = [] + jars.addAll(defaultConfigData.jars) + jars.addAll(buildTypeData.jars) + + // the order of the libraries is important. In descending order: + // build types, defaultConfig. + List<AndroidDependency> libs = [] + libs.addAll(buildTypeData.libraries) + libs.addAll(defaultConfigData.libraries) + def variantConfig = new VariantConfiguration( defaultConfigData.productFlavor, defaultConfigData.sourceSet, buildTypeData.buildType, buildTypeData.sourceSet, VariantConfiguration.Type.LIBRARY) + variantConfig.setJarDependencies(jars) + variantConfig.setAndroidDependencies(libs) + ProductionAppVariant variant = new ProductionAppVariant(variantConfig) + variants.add(variant) - def prepareDependenciesTask = createPrepareDependenciesTask(variant) + def prepareDependenciesTask = createPrepareDependenciesTask(variant, configDependencies) // Add a task to process the manifest(s) ProcessManifestTask processManifestTask = createProcessManifestTask(variant, DIR_BUNDLES) @@ -171,7 +199,8 @@ class LibraryPlugin extends BasePlugin implements Plugin<Project> { // configure the variant to be testable. variantConfig.output = new BundleDependency( - project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}")) { + project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"), + variant.getName()) { @Override List<AndroidDependency> getDependencies() { @@ -185,15 +214,29 @@ class LibraryPlugin extends BasePlugin implements Plugin<Project> { void createTestTasks(ProductionAppVariant testedVariant) { ProductFlavorData defaultConfigData = getDefaultConfigData(); + List<ConfigurationDependencies> configDependencies = [] + configDependencies.add(defaultConfigData.testConfigDependencies) + + // list of dependency to set on the variantConfig + List<JarDependency> jars = [] + jars.addAll(defaultConfigData.testConfigDependencies.jars) + + // the order of the libraries is important. In descending order: + // build types, defaultConfig. + List<AndroidDependency> libs = [] + libs.addAll(defaultConfigData.testConfigDependencies.libraries) + def testVariantConfig = new VariantConfiguration( defaultConfigData.productFlavor, defaultConfigData.testSourceSet, debugBuildTypeData.buildType, null, VariantConfiguration.Type.TEST, testedVariant.config) - // TODO: add actual dependencies - testVariantConfig.setAndroidDependencies(null) + + testVariantConfig.setJarDependencies(jars) + testVariantConfig.setAndroidDependencies(libs) def testVariant = new TestAppVariant(testVariantConfig,) - createTestTasks(testVariant, testedVariant) + variants.add(testVariant) + createTestTasks(testVariant, testedVariant, configDependencies) } @Override diff --git a/gradle/src/main/groovy/com/android/build/gradle/PrepareDependenciesTask.groovy b/gradle/src/main/groovy/com/android/build/gradle/PrepareDependenciesTask.groovy index f104b30..121434a 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/PrepareDependenciesTask.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/PrepareDependenciesTask.groovy @@ -37,7 +37,6 @@ class PrepareDependenciesTask extends BaseTask { return bundles.keySet() } - @OutputDirectories Iterable<File> getExplodedBundles() { return bundles.values() diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java new file mode 100644 index 0000000..315daf8 --- /dev/null +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.android.build.gradle.internal; + +import com.android.builder.AndroidDependency; +import com.android.builder.BundleDependency; +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.tasks.diagnostics.internal.GraphRenderer; +import org.gradle.api.tasks.diagnostics.internal.TextReportRenderer; +import org.gradle.logging.StyledTextOutput; +import org.gradle.util.GUtil; + +import java.io.IOException; +import java.util.List; + +import static org.gradle.logging.StyledTextOutput.Style.Description; +import static org.gradle.logging.StyledTextOutput.Style.Identifier; +import static org.gradle.logging.StyledTextOutput.Style.Info; + +/** + * android version of the AsciiReportRenderer that outputs Android Library dependencies. + */ +public class AndroidAsciiReportRenderer extends TextReportRenderer { + private boolean hasConfigs; + private boolean hasCyclicDependencies; + private GraphRenderer renderer; + + @Override + public void startProject(Project project) { + super.startProject(project); + hasConfigs = false; + hasCyclicDependencies = false; + } + + @Override + public void completeProject(Project project) { + if (!hasConfigs) { + getTextOutput().withStyle(Info).println("No dependencies"); + } + super.completeProject(project); + } + + public void startVariant(final ApplicationVariant variant) { + if (hasConfigs) { + getTextOutput().println(); + } + hasConfigs = true; + renderer = new GraphRenderer(getTextOutput()); + renderer.visit(new Action<StyledTextOutput>() { + public void execute(StyledTextOutput styledTextOutput) { + getTextOutput().withStyle(Identifier).text(variant.getName()); + getTextOutput().withStyle(Description).text(""); + } + }, true); + } + + private String getDescription(Configuration configuration) { + return GUtil.isTrue( + configuration.getDescription()) ? " - " + configuration.getDescription() : ""; + } + + public void completeConfiguration(ApplicationVariant variant) {} + + public void render(ApplicationVariant variant) throws IOException { + List<AndroidDependency> libraries = variant.getVariantConfiguration().getDirectLibraries(); + + renderNow(libraries); + } + + void renderNow(List<AndroidDependency> libraries) { + if (libraries.isEmpty()) { + getTextOutput().withStyle(Info).text("No dependencies"); + getTextOutput().println(); + return; + } + + renderChildren(libraries); + } + + public void complete() throws IOException { + if (hasCyclicDependencies) { + getTextOutput().withStyle(Info).println( + "\n(*) - dependencies omitted (listed previously)"); + } + + super.complete(); + } + + private void render(final AndroidDependency lib, boolean lastChild) { + renderer.visit(new Action<StyledTextOutput>() { + public void execute(StyledTextOutput styledTextOutput) { + getTextOutput().text(((BundleDependency)lib).getName()); + } + }, lastChild); + + renderChildren(lib.getDependencies()); + } + + private void renderChildren(List<AndroidDependency> libraries) { + renderer.startChildren(); + for (int i = 0; i < libraries.size(); i++) { + AndroidDependency lib = libraries.get(i); + render(lib, i == libraries.size() - 1); + } + renderer.completeChildren(); + } +} diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidDependencyImpl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidDependencyImpl.groovy index 8cadb24..96482d1 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidDependencyImpl.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidDependencyImpl.groovy @@ -20,9 +20,12 @@ import com.android.builder.BundleDependency class AndroidDependencyImpl extends BundleDependency { final List<AndroidDependency> dependencies; + final File bundle - AndroidDependencyImpl(File explodedBundle, List<AndroidDependency> dependencies) { - super(explodedBundle) + AndroidDependencyImpl(String name, File explodedBundle, List<AndroidDependency> dependencies, + File bundle) { + super(explodedBundle, name) this.dependencies = dependencies + this.bundle = bundle } } diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/ApplicationVariant.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/ApplicationVariant.groovy index 826f206..c3e2850 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/internal/ApplicationVariant.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/ApplicationVariant.groovy @@ -56,6 +56,10 @@ public abstract class ApplicationVariant { return config.buildConfigLines } + public VariantConfiguration getVariantConfiguration() { + return config + } + abstract String getName() abstract String getDescription() diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/BuildTypeData.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/BuildTypeData.groovy index 679b5e3..1b543d5 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/internal/BuildTypeData.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/BuildTypeData.groovy @@ -20,16 +20,16 @@ import com.android.builder.BuildType import org.gradle.api.Project import org.gradle.api.Task -class BuildTypeData { - final BuildType buildType +class BuildTypeData extends ConfigurationDependencies { - final AndroidSourceSet sourceSet + final BuildType buildType final Task assembleTask BuildTypeData(BuildType buildType, AndroidSourceSet sourceSet, Project project) { + super(project, sourceSet) + this.buildType = buildType - this.sourceSet = sourceSet assembleTask = project.tasks.add("assemble${buildType.name.capitalize()}") assembleTask.description = "Assembles all ${buildType.name.capitalize()} builds" diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/ConfigurationDependencies.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/ConfigurationDependencies.groovy new file mode 100644 index 0000000..1e48c10 --- /dev/null +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/ConfigurationDependencies.groovy @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.android.build.gradle.internal + +import com.android.build.gradle.AndroidSourceSet +import com.android.builder.JarDependency +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration + +/** + * Object that represents the dependencies of a configuration, and optionally contains the + * dependencies for a test config for the given config. + */ +class ConfigurationDependencies { + + final Project project + final AndroidSourceSet sourceSet + ConfigurationDependencies testConfigDependencies; + + ConfigurationDependencies(Project project, AndroidSourceSet sourceSet) { + this.project = project + this.sourceSet = sourceSet + } + + List<AndroidDependencyImpl> libraries + List<JarDependency> jars + + Configuration getConfiguration() { + return project.configurations[sourceSet.compileConfigurationName] + } + + String getConfigBaseName() { + return sourceSet.name + } +} diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/ProductFlavorData.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/ProductFlavorData.groovy index 68f59ff..39266b4 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/internal/ProductFlavorData.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/ProductFlavorData.groovy @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.build.gradle.internal import com.android.build.gradle.AndroidSourceSet import org.gradle.api.Project import org.gradle.api.Task -class ProductFlavorData { - final ProductFlavorDsl productFlavor +class ProductFlavorData extends ConfigurationDependencies { - final AndroidSourceSet sourceSet + final ProductFlavorDsl productFlavor final AndroidSourceSet testSourceSet @@ -31,10 +31,12 @@ class ProductFlavorData { ProductFlavorData(ProductFlavorDsl productFlavor, AndroidSourceSet sourceSet, AndroidSourceSet testSourceSet, Project project) { - this.productFlavor = productFlavor + super(project, sourceSet) - this.sourceSet = sourceSet + this.productFlavor = productFlavor this.testSourceSet = testSourceSet + + setTestConfigDependencies(new ConfigurationDependencies(project, testSourceSet)) } |