Refactor dependency classes in their package.
[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.dependency.AndroidDependency
25 import com.android.builder.BuilderConstants
26 import com.android.builder.dependency.BundleDependency
27 import com.android.builder.dependency.DependencyContainer
28 import com.android.builder.dependency.JarDependency
29 import com.android.builder.dependency.ManifestDependency
30 import com.android.builder.VariantConfiguration
31 import com.google.common.collect.Sets
32 import org.gradle.api.Plugin
33 import org.gradle.api.Project
34 import org.gradle.api.internal.project.ProjectInternal
35 import org.gradle.api.plugins.MavenPlugin
36 import org.gradle.api.tasks.Sync
37 import org.gradle.api.tasks.bundling.Jar
38 import org.gradle.api.tasks.bundling.Zip
39 import org.gradle.internal.reflect.Instantiator
40 import org.gradle.tooling.BuildException
41
42 import javax.inject.Inject
43 /**
44  * Gradle plugin class for 'library' projects.
45  */
46 public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
47
48     private final static String DIR_BUNDLES = "bundles";
49
50     LibraryExtension extension
51     BuildTypeData debugBuildTypeData
52     BuildTypeData releaseBuildTypeData
53
54     @Inject
55     public LibraryPlugin(Instantiator instantiator) {
56         super(instantiator)
57     }
58
59     @Override
60     void apply(Project project) {
61         super.apply(project)
62
63         extension = project.extensions.create('android', LibraryExtension,
64                 this, (ProjectInternal) project, instantiator)
65         setDefaultConfig(extension.defaultConfig, extension.sourceSetsContainer)
66
67         // create the source sets for the build type.
68         // the ones for the main product flavors are handled by the base plugin.
69         def debugSourceSet = extension.sourceSetsContainer.create(BuilderConstants.DEBUG)
70         def releaseSourceSet = extension.sourceSetsContainer.create(BuilderConstants.RELEASE)
71
72         debugBuildTypeData = new BuildTypeData(extension.debug, debugSourceSet, project)
73         releaseBuildTypeData = new BuildTypeData(extension.release, releaseSourceSet, project)
74         project.tasks.assemble.dependsOn debugBuildTypeData.assembleTask
75         project.tasks.assemble.dependsOn releaseBuildTypeData.assembleTask
76
77         createConfigurations(releaseSourceSet)
78     }
79
80     void createConfigurations(AndroidSourceSet releaseSourceSet) {
81         // The library artifact is published for the "default" configuration so we make
82         // sure "default" extends from the actual configuration used for building.
83         project.configurations["default"].extendsFrom(
84                 project.configurations[mainSourceSet.getPackageConfigurationName()])
85         project.configurations["default"].extendsFrom(
86                 project.configurations[releaseSourceSet.getPackageConfigurationName()])
87
88         project.plugins.withType(MavenPlugin) {
89             project.conf2ScopeMappings.addMapping(300,
90                     project.configurations[mainSourceSet.getCompileConfigurationName()],
91                     "compile")
92             project.conf2ScopeMappings.addMapping(300,
93                     project.configurations[releaseSourceSet.getCompileConfigurationName()],
94                     "compile")
95             // TODO -- figure out the package configuration
96 //            project.conf2ScopeMappings.addMapping(300,
97 //                    project.configurations[mainSourceSet.getPackageConfigurationName()],
98 //                    "runtime")
99 //            project.conf2ScopeMappings.addMapping(300,
100 //                    project.configurations[releaseSourceSet.getPackageConfigurationName()],
101 //                    "runtime")
102         }
103     }
104
105     @Override
106     protected void doCreateAndroidTasks() {
107         // resolve dependencies for all config
108         List<ConfigurationDependencies> dependencies = []
109         dependencies.add(debugBuildTypeData)
110         dependencies.add(releaseBuildTypeData)
111         resolveDependencies(dependencies)
112
113         ProductionAppVariant testedVariant = createLibraryTasks(debugBuildTypeData, false)
114         ProductionAppVariant nonTestedVariant = createLibraryTasks(releaseBuildTypeData, true)
115         TestAppVariant testVariant = createTestTasks(testedVariant)
116
117         // add the not-tested build variant.
118         extension.buildVariants.add(
119                 instantiator.newInstance(DefaultBuildVariant.class, nonTestedVariant))
120
121         // and add the test variant
122         DefaultBuildVariant testBuildVariant = instantiator.newInstance(
123                 DefaultBuildVariant.class, testVariant)
124         extension.testBuildVariants.add(testBuildVariant)
125
126         // and finally the tested variant
127         extension.buildVariants.add(
128                 instantiator.newInstance(DefaultBuildVariant.class,
129                         testedVariant, testBuildVariant))
130
131     }
132
133     private ProductionAppVariant createLibraryTasks(BuildTypeData buildTypeData,
134                                                     boolean publishArtifact) {
135         ProductFlavorData defaultConfigData = getDefaultConfigData();
136
137         // the order of the libraries is important. In descending order:
138         // build type, defaultConfig.
139         List<ConfigurationDependencies> configDependencies = []
140         configDependencies.add(buildTypeData)
141         configDependencies.add(defaultConfigData)
142
143         def variantConfig = new VariantConfiguration(
144                 defaultConfigData.productFlavor, defaultConfigData.sourceSet,
145                 buildTypeData.buildType, buildTypeData.sourceSet,
146                 VariantConfiguration.Type.LIBRARY, project.name)
147
148         variantConfig.setDependencies(configDependencies)
149
150         String packageName = variantConfig.getPackageFromManifest()
151         if (packageName == null) {
152             throw new BuildException("Failed to read manifest")
153         }
154
155         ProductionAppVariant variant = new ProductionAppVariant(variantConfig)
156         variants.add(variant)
157
158         createPrepareDependenciesTask(variant, configDependencies)
159
160         // Add a task to process the manifest(s)
161         createProcessManifestTask(variant, DIR_BUNDLES)
162
163         // Add a task to compile renderscript files.
164         createRenderscriptTask(variant)
165
166         // Add a task to merge the resource folders
167         createMergeResourcesTask(variant, "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/res",
168                 false /*process9Patch*/)
169
170         // Add a task to merge the assets folders
171         createMergeAssetsTask(variant,
172                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/assets")
173
174         // Add a task to create the BuildConfig class
175         createBuildConfigTask(variant)
176
177         // Add a task to generate resource source files, directing the location
178         // of the r.txt file to be directly in the bundle.
179         createProcessResTask(variant, "$project.buildDir/$DIR_BUNDLES/${variant.dirName}")
180
181         // process java resources
182         createProcessJavaResTask(variant)
183
184         createAidlTask(variant)
185
186         // Add a compile task
187         createCompileTask(variant, null/*testedVariant*/)
188
189         // jar the classes.
190         Jar jar = project.tasks.add("package${buildTypeData.buildType.name.capitalize()}Jar", Jar);
191         jar.dependsOn variant.javaCompileTask, variant.processJavaResources
192         jar.from(variant.javaCompileTask.outputs);
193         jar.from(variant.processJavaResources.destinationDir)
194
195         jar.destinationDir = project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}")
196         jar.archiveName = "classes.jar"
197         packageName = packageName.replace('.', '/');
198         jar.exclude(packageName + "/R.class")
199         jar.exclude(packageName + "/R\$*.class")
200         jar.exclude(packageName + "/BuildConfig.class")
201
202         // package the aidl files into the bundle folder
203         Sync packageAidl = project.tasks.add("package${variant.name}Aidl", Sync)
204         // packageAidl from 3 sources. the order is important to make sure the override works well.
205         packageAidl.from(defaultConfigData.sourceSet.aidl.directories,
206                 buildTypeData.sourceSet.aidl.directories).include("**/*.aidl")
207         packageAidl.into(project.file(
208                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_AIDL"))
209
210         // package the renderscript header files files into the bundle folder
211         Sync packageRenderscript = project.tasks.add("package${variant.name}Renderscript", Sync)
212         // package from 3 sources. the order is important to make sure the override works well.
213         packageRenderscript.from(defaultConfigData.sourceSet.renderscript.directories,
214                 buildTypeData.sourceSet.renderscript.directories).include("**/*.rsh")
215         packageRenderscript.into(project.file(
216                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_RENDERSCRIPT"))
217
218         // package the renderscript header files files into the bundle folder
219         Sync packageLocalJar = project.tasks.add("package${variant.name}LocalJar", Sync)
220         packageLocalJar.from(getLocalJarFileList(configDependencies))
221         packageLocalJar.into(project.file(
222                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.LIBS_FOLDER"))
223
224         Zip bundle = project.tasks.add("bundle${variant.name}", Zip)
225         bundle.dependsOn jar, packageAidl, packageRenderscript, packageLocalJar
226         bundle.setDescription("Assembles a bundle containing the library in ${variant.name}.");
227         bundle.destinationDir = project.file("$project.buildDir/libs")
228         bundle.extension = BuilderConstants.EXT_LIB_ARCHIVE
229         if (variant.baseName != BuilderConstants.RELEASE) {
230             bundle.classifier = variant.baseName
231         }
232         bundle.from(project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"))
233
234         variant.packageLibTask = bundle
235         variant.outputFile = bundle.archivePath
236
237         if (publishArtifact) {
238             // add the artifact that will be published
239             project.artifacts.add("default", bundle)
240         }
241
242         buildTypeData.assembleTask.dependsOn bundle
243         variant.assembleTask = bundle
244
245         // configure the variant to be testable.
246         variantConfig.output = new BundleDependency(
247                 project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"),
248                 variant.getName()) {
249
250             @Override
251             List<AndroidDependency> getDependencies() {
252                 return variantConfig.directLibraries
253             }
254
255             @Override
256             List<ManifestDependency> getManifestDependencies() {
257                 return variantConfig.directLibraries
258             }
259         };
260
261         return variant
262     }
263
264     static Object[] getLocalJarFileList(List<? extends DependencyContainer> containerList) {
265         Set<File> files = Sets.newHashSet()
266         for (DependencyContainer dependencyContainer : containerList) {
267             for (JarDependency jarDependency : dependencyContainer.localDependencies) {
268                 files.add(jarDependency.jarFile)
269             }
270         }
271
272         return files.toArray()
273     }
274
275     private TestAppVariant createTestTasks(ProductionAppVariant testedVariant) {
276         ProductFlavorData defaultConfigData = getDefaultConfigData();
277
278         // the order of the libraries is important. In descending order:
279         // build types, defaultConfig.
280         List<ConfigurationDependencies> configDependencies = []
281         configDependencies.add(defaultConfigData.testConfigDependencies)
282
283         def testVariantConfig = new VariantConfiguration(
284                 defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
285                 debugBuildTypeData.buildType, null,
286                 VariantConfiguration.Type.TEST, testedVariant.config, project.name)
287
288         testVariantConfig.setDependencies(configDependencies)
289
290         def testVariant = new TestAppVariant(testVariantConfig,)
291         variants.add(testVariant)
292         createTestTasks(testVariant, testedVariant, configDependencies, true /*mainTestTask*/)
293
294         return testVariant
295     }
296
297     @Override
298     protected String getTarget() {
299         return extension.compileSdkVersion
300     }
301 }