Clean dependencies of published libraries.
[android/platform/tools/build.git] / gradle / src / main / groovy / com / android / build / gradle / LibraryPlugin.groovy
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.build.gradle
17 import com.android.SdkConstants
18 import com.android.build.gradle.internal.BuildTypeData
19 import com.android.build.gradle.internal.DefaultBuildVariant
20 import com.android.build.gradle.internal.ProductFlavorData
21 import com.android.build.gradle.internal.ProductionAppVariant
22 import com.android.build.gradle.internal.TestAppVariant
23 import com.android.build.gradle.internal.dependency.ConfigurationDependencies
24 import com.android.builder.AndroidDependency
25 import com.android.builder.BuilderConstants
26 import com.android.builder.BundleDependency
27 import com.android.builder.JarDependency
28 import com.android.builder.ManifestDependency
29 import com.android.builder.VariantConfiguration
30 import org.gradle.api.Plugin
31 import org.gradle.api.Project
32 import org.gradle.api.internal.project.ProjectInternal
33 import org.gradle.api.plugins.MavenPlugin
34 import org.gradle.api.tasks.Copy
35 import org.gradle.api.tasks.bundling.Jar
36 import org.gradle.api.tasks.bundling.Zip
37 import org.gradle.internal.reflect.Instantiator
38
39 import javax.inject.Inject
40 /**
41  * Gradle plugin class for 'library' projects.
42  */
43 public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
44
45     private final static String DIR_BUNDLES = "bundles";
46
47     LibraryExtension extension
48     BuildTypeData debugBuildTypeData
49     BuildTypeData releaseBuildTypeData
50
51     @Inject
52     public LibraryPlugin(Instantiator instantiator) {
53         super(instantiator)
54     }
55
56     @Override
57     void apply(Project project) {
58         super.apply(project)
59
60         extension = project.extensions.create('android', LibraryExtension,
61                 this, (ProjectInternal) project, instantiator)
62         setDefaultConfig(extension.defaultConfig, extension.sourceSetsContainer)
63
64         // create the source sets for the build type.
65         // the ones for the main product flavors are handled by the base plugin.
66         def debugSourceSet = extension.sourceSetsContainer.create(BuilderConstants.DEBUG)
67         def releaseSourceSet = extension.sourceSetsContainer.create(BuilderConstants.RELEASE)
68
69         debugBuildTypeData = new BuildTypeData(extension.debug, debugSourceSet, project)
70         releaseBuildTypeData = new BuildTypeData(extension.release, releaseSourceSet, project)
71         project.tasks.assemble.dependsOn debugBuildTypeData.assembleTask
72         project.tasks.assemble.dependsOn releaseBuildTypeData.assembleTask
73
74         createConfigurations(releaseSourceSet)
75     }
76
77     void createConfigurations(AndroidSourceSet releaseSourceSet) {
78         // The library artifact is published for the "default" configuration so we make
79         // sure "default" extends from the actual configuration used for building.
80         project.configurations["default"].extendsFrom(
81                 project.configurations[mainSourceSet.getPackageConfigurationName()])
82         project.configurations["default"].extendsFrom(
83                 project.configurations[releaseSourceSet.getPackageConfigurationName()])
84
85         project.plugins.withType(MavenPlugin) {
86             project.conf2ScopeMappings.addMapping(300,
87                     project.configurations[mainSourceSet.getCompileConfigurationName()],
88                     "compile")
89             project.conf2ScopeMappings.addMapping(300,
90                     project.configurations[releaseSourceSet.getCompileConfigurationName()],
91                     "compile")
92             // TODO -- figure out the package configuration
93 //            project.conf2ScopeMappings.addMapping(300,
94 //                    project.configurations[mainSourceSet.getPackageConfigurationName()],
95 //                    "runtime")
96 //            project.conf2ScopeMappings.addMapping(300,
97 //                    project.configurations[releaseSourceSet.getPackageConfigurationName()],
98 //                    "runtime")
99         }
100     }
101
102     @Override
103     protected void doCreateAndroidTasks() {
104         // resolve dependencies for all config
105         List<ConfigurationDependencies> dependencies = []
106         dependencies.add(debugBuildTypeData)
107         dependencies.add(releaseBuildTypeData)
108         resolveDependencies(dependencies)
109
110         ProductionAppVariant testedVariant = createLibraryTasks(debugBuildTypeData, false)
111         ProductionAppVariant nonTestedVariant = createLibraryTasks(releaseBuildTypeData, true)
112         TestAppVariant testVariant = createTestTasks(testedVariant)
113
114         // add the not-tested build variant.
115         extension.buildVariants.add(
116                 instantiator.newInstance(DefaultBuildVariant.class, nonTestedVariant))
117
118         // and add the test variant
119         DefaultBuildVariant testBuildVariant = instantiator.newInstance(
120                 DefaultBuildVariant.class, testVariant)
121         extension.testBuildVariants.add(testBuildVariant)
122
123         // and finally the tested variant
124         extension.buildVariants.add(
125                 instantiator.newInstance(DefaultBuildVariant.class,
126                         testedVariant, testBuildVariant))
127
128     }
129
130     private ProductionAppVariant createLibraryTasks(BuildTypeData buildTypeData,
131                                                     boolean publishArtifact) {
132         ProductFlavorData defaultConfigData = getDefaultConfigData();
133
134         List<ConfigurationDependencies> configDependencies = []
135         configDependencies.add(defaultConfigData)
136         configDependencies.add(buildTypeData)
137
138         // list of dependency to set on the variantConfig
139         List<JarDependency> jars = []
140         jars.addAll(defaultConfigData.jars)
141         jars.addAll(buildTypeData.jars)
142
143         // the order of the libraries is important. In descending order:
144         // build types, defaultConfig.
145         List<AndroidDependency> libs = []
146         libs.addAll(buildTypeData.libraries)
147         libs.addAll(defaultConfigData.libraries)
148
149         def variantConfig = new VariantConfiguration(
150                 defaultConfigData.productFlavor, defaultConfigData.sourceSet,
151                 buildTypeData.buildType, buildTypeData.sourceSet,
152                 VariantConfiguration.Type.LIBRARY)
153
154         variantConfig.setJarDependencies(jars)
155         variantConfig.setAndroidDependencies(libs)
156
157         ProductionAppVariant variant = new ProductionAppVariant(variantConfig)
158         variants.add(variant)
159
160         createPrepareDependenciesTask(variant, configDependencies)
161
162         // Add a task to process the manifest(s)
163         createProcessManifestTask(variant, DIR_BUNDLES)
164
165         // Add a task to compile renderscript files.
166         createRenderscriptTask(variant)
167
168         // Add a task to merge the resource folders
169         createMergeResourcesTask(variant, "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/res",
170                 false /*process9Patch*/)
171
172         // Add a task to create the BuildConfig class
173         createBuildConfigTask(variant)
174
175         // Add a task to generate resource source files
176         createProcessResTask(variant)
177
178         // process java resources
179         createProcessJavaResTask(variant)
180
181         createAidlTask(variant)
182
183         // Add a compile task
184         createCompileTask(variant, null/*testedVariant*/)
185
186         // jar the classes.
187         Jar jar = project.tasks.add("package${buildTypeData.buildType.name.capitalize()}Jar", Jar);
188         jar.dependsOn variant.javaCompileTask, variant.processJavaResources
189         jar.from(variant.javaCompileTask.outputs);
190         jar.from(variant.processJavaResources.destinationDir)
191
192         jar.destinationDir = project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}")
193         jar.archiveName = "classes.jar"
194         String packageName = variantConfig.getPackageFromManifest().replace('.', '/');
195         jar.exclude(packageName + "/R.class")
196         jar.exclude(packageName + "/R\$*.class")
197
198         // package the aidl files into the bundle folder
199         Copy packageAidl = project.tasks.add("package${variant.name}Aidl", Copy)
200         // packageAidl from 3 sources. the order is important to make sure the override works well.
201         packageAidl.from(defaultConfigData.sourceSet.aidl.directories,
202                 buildTypeData.sourceSet.aidl.directories).include("**/*.aidl")
203         packageAidl.into(project.file(
204                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_AIDL"))
205
206         // package the renderscript header files files into the bundle folder
207         Copy packageRenderscript = project.tasks.add("package${variant.name}Renderscript", Copy)
208         // packageAidl from 3 sources. the order is important to make sure the override works well.
209         packageRenderscript.from(defaultConfigData.sourceSet.renderscript.directories,
210                 buildTypeData.sourceSet.renderscript.directories).include("**/*.rsh")
211         packageRenderscript.into(project.file(
212                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_RENDERSCRIPT"))
213
214         // package the R symbol text file into the bundle folder
215         Copy packageSymbol = project.tasks.add("package${variant.name}Symbols", Copy)
216         packageSymbol.dependsOn variant.processResourcesTask
217         packageSymbol.from(variant.processResourcesTask.textSymbolDir)
218         packageSymbol.into(project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"))
219
220         Zip bundle = project.tasks.add("bundle${variant.name}", Zip)
221         bundle.dependsOn jar, packageAidl, packageSymbol, packageRenderscript
222         bundle.setDescription("Assembles a bundle containing the library in ${variant.name}.");
223         bundle.destinationDir = project.file("$project.buildDir/libs")
224         bundle.extension = BuilderConstants.EXT_LIB_ARCHIVE
225         if (variant.baseName != BuilderConstants.RELEASE) {
226             bundle.classifier = variant.baseName
227         }
228         bundle.from(project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"))
229
230         variant.packageLibTask = bundle
231         variant.outputFile = bundle.archivePath
232
233         if (publishArtifact) {
234             // add the artifact that will be published
235             project.artifacts.add("default", bundle)
236         }
237
238         buildTypeData.assembleTask.dependsOn bundle
239         variant.assembleTask = bundle
240
241         // configure the variant to be testable.
242         variantConfig.output = new BundleDependency(
243                 project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"),
244                 variant.getName()) {
245
246             @Override
247             List<AndroidDependency> getDependencies() {
248                 return variantConfig.directLibraries
249             }
250
251             @Override
252             List<ManifestDependency> getManifestDependencies() {
253                 return variantConfig.directLibraries
254             }
255         };
256
257         return variant
258     }
259
260     private TestAppVariant createTestTasks(ProductionAppVariant testedVariant) {
261         ProductFlavorData defaultConfigData = getDefaultConfigData();
262
263         List<ConfigurationDependencies> configDependencies = []
264         configDependencies.add(defaultConfigData.testConfigDependencies)
265
266         // list of dependency to set on the variantConfig
267         List<JarDependency> jars = []
268         jars.addAll(defaultConfigData.testConfigDependencies.jars)
269
270         // the order of the libraries is important. In descending order:
271         // build types, defaultConfig.
272         List<AndroidDependency> libs = []
273         libs.addAll(defaultConfigData.testConfigDependencies.libraries)
274
275         def testVariantConfig = new VariantConfiguration(
276                 defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
277                 debugBuildTypeData.buildType, null,
278                 VariantConfiguration.Type.TEST, testedVariant.config)
279
280         testVariantConfig.setJarDependencies(jars)
281         testVariantConfig.setAndroidDependencies(libs)
282
283         def testVariant = new TestAppVariant(testVariantConfig,)
284         variants.add(testVariant)
285         createTestTasks(testVariant, testedVariant, configDependencies, true /*mainTestTask*/)
286
287         return testVariant
288     }
289
290     @Override
291     protected String getTarget() {
292         return extension.target
293     }
294 }