1import com.android.build.gradle.internal.coverage.JacocoReportTask
2import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
3
4buildscript {
5    repositories {
6        maven { url '../../prebuilts/gradle-plugin' }
7        maven { url '../../prebuilts/tools/common/m2/repository' }
8        maven { url '../../prebuilts/tools/common/m2/internal' }
9        maven { url "../../prebuilts/maven_repo/android" }
10    }
11    dependencies {
12        classpath 'com.android.tools.build:gradle:2.1.2'
13    }
14}
15
16ext.supportVersion = '24.0.1'
17ext.extraVersion = 34
18ext.supportRepoOut = ''
19ext.buildToolsVersion = '23.0.2'
20ext.buildNumber = Integer.toString(ext.extraVersion)
21
22/*
23 * With the build server you are given two env variables.
24 * The OUT_DIR is a temporary directory you can use to put things during the build.
25 * The DIST_DIR is where you want to save things from the build.
26 *
27 * The build server will copy the contents of DIST_DIR to somewhere and make it available.
28 */
29if (System.env.DIST_DIR != null && System.env.OUT_DIR != null) {
30    buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build').getCanonicalFile()
31    project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
32
33    // the build server does not pass the build number so we infer it from the last folder of the dist path.
34    ext.buildNumber = project.ext.distDir.getName()
35} else {
36    buildDir = file('../../out/host/gradle/frameworks/support/build')
37    project.ext.distDir = file('../../out/dist')
38}
39
40ext.supportRepoOut = new File(buildDir, 'support_repo')
41ext.testApkDistOut = ext.distDir
42
43// Main task called by the build server.
44task(createArchive) << {
45}
46
47
48// upload anchor for subprojects to upload their artifacts
49// to the local repo.
50task(mainUpload) << {
51}
52
53// repository creation task
54task createRepository(type: Zip, dependsOn: mainUpload) {
55    from project.ext.supportRepoOut
56    destinationDir project.ext.distDir
57    into 'm2repository'
58    baseName = String.format("sdk-repo-linux-m2repository-%s", project.ext.buildNumber)
59}
60createArchive.dependsOn createRepository
61
62// prepare repository with older versions
63task unzipRepo(type: Copy) {
64    from "$rootDir/../../prebuilts/maven_repo/android"
65    into project.ext.supportRepoOut
66}
67
68unzipRepo.doFirst {
69    project.ext.supportRepoOut.deleteDir()
70    project.ext.supportRepoOut.mkdirs()
71}
72
73// anchor for prepare repo. This is post unzip + sourceProp.
74task(prepareRepo) << {
75}
76
77
78import android.support.build.ApiModule
79import com.google.common.io.Files
80import com.google.common.base.Charsets
81
82task(createXml) << {
83    def repoArchive = createRepository.archivePath
84    def repoArchiveName = createRepository.archiveName
85    def size = repoArchive.length()
86    def sha1 = getSha1(repoArchive)
87
88    def xml =
89"<sdk:sdk-addon xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:sdk=\"http://schemas.android.com/sdk/android/addon/6\">\n\
90  <sdk:extra>\n\
91    <sdk:revision>\n\
92      <sdk:major>${project.ext.extraVersion}</sdk:major>\n\
93    </sdk:revision>\n\
94    <sdk:vendor-display>Android</sdk:vendor-display>\n\
95    <sdk:vendor-id>android</sdk:vendor-id>\n\
96    <sdk:name-display>Local Maven repository for Support Libraries</sdk:name-display>\n\
97    <sdk:path>m2repository</sdk:path>\n\
98    <sdk:archives>\n\
99      <sdk:archive>\n\
100       <sdk:size>${size}</sdk:size>\n\
101       <sdk:checksum type=\"sha1\">${sha1}</sdk:checksum>\n\
102       <sdk:url>${repoArchiveName}</sdk:url>\n\
103      </sdk:archive>\n\
104    </sdk:archives>\n\
105  </sdk:extra>\n\
106</sdk:sdk-addon>"
107
108    Files.write(xml, new File(project.ext.distDir, 'repo-extras.xml'), Charsets.UTF_8)
109}
110createArchive.dependsOn createXml
111
112task(createSourceProp) << {
113    def sourceProp =
114"Extra.VendorDisplay=Android\n\
115Extra.Path=m2repository\n\
116Archive.Arch=ANY\n\
117Extra.NameDisplay=Android Support Repository\n\
118Archive.Os=ANY\n\
119Pkg.Desc=Local Maven repository for Support Libraries\n\
120Pkg.Revision=${project.ext.extraVersion}.0.0\n\
121Extra.VendorId=android"
122
123    Files.write(sourceProp, new File(project.ext.supportRepoOut, 'source.properties'), Charsets.UTF_8)
124}
125createSourceProp.dependsOn unzipRepo
126prepareRepo.dependsOn createSourceProp
127
128import com.google.common.hash.HashCode
129import com.google.common.hash.HashFunction
130import com.google.common.hash.Hashing
131import java.nio.charset.Charset
132
133def getSha1(File inputFile) {
134    HashFunction hashFunction = Hashing.sha1()
135    HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charset.forName("UTF-8"))
136    return hashCode.toString()
137}
138
139def createApiSourceSets(Project subProject, List<ApiModule> apiModules) {
140    subProject.ext._apiModules = apiModules
141    subProject.ext.allSS = []
142    if (gradle.ext.studioCompat.enableApiModules) {
143        // nothing to do, they are all modules
144        return
145    }
146    // create a jar task for the api specific internal implementations
147    def internalJar = subProject.tasks.create(name: "internalJar", type: Jar) {
148        baseName "internal_impl"
149    }
150    apiModules.each { ApiModule apiModule ->
151        apiModule.sourceSet = createApiSourceset(subProject, apiModule.folderName, apiModule.folderName,
152                apiModule.apiForSourceSet.toString(), apiModule.prev == null ? null : apiModule.prev.sourceSet)
153        subProject.ext.allSS.add(apiModule.sourceSet)
154    }
155    subProject.android.libraryVariants.all { variant ->
156        variant.javaCompile.dependsOn internalJar
157    }
158}
159
160def createApiSourceset(Project subProject, String name, String folder, String apiLevel,
161                       SourceSet previousSource) {
162    def sourceSet = subProject.sourceSets.create(name)
163    sourceSet.java.srcDirs = [folder]
164
165    def configName = sourceSet.getCompileConfigurationName()
166
167    subProject.getDependencies().add(configName, getAndroidPrebuilt(apiLevel))
168    if (previousSource != null) {
169        setupDependencies(subProject, configName, previousSource)
170    }
171    subProject.ext.allSS.add(sourceSet)
172    subProject.tasks.internalJar.from sourceSet.output
173    return sourceSet
174}
175
176def setApiModuleDependencies(Project subProject, DependencyHandler handler, List extraDeps) {
177    if (gradle.ext.studioCompat.enableApiModules) {
178        subProject.android.enforceUniquePackageName=false
179        // add dependency on the latest module
180        handler.compile(project(subProject.ext._apiModules.last().moduleName))
181    } else {
182        handler.compile(files(subProject.tasks.internalJar.archivePath))
183        def firstModule = subProject.ext._apiModules[0]
184        extraDeps.each { dep ->
185            handler."${firstModule.folderName}Compile"(project(dep))
186            handler.compile(project(dep))
187        }
188
189    }
190}
191
192def setupDependencies(Project subProject, String configName, SourceSet previousSourceSet) {
193    subProject.getDependencies().add(configName, previousSourceSet.output)
194    subProject.getDependencies().add(configName, previousSourceSet.compileClasspath)
195}
196
197subprojects {
198    // Change buildDir first so that all plugins pick up the new value.
199    project.buildDir = project.file("$project.parent.buildDir/../$project.name/build")
200    // current SDK is set in studioCompat.gradle
201    project.ext.currentSdk = gradle.ext.currentSdk
202    apply plugin: 'maven'
203    project.ext.createApiSourceSets = this.&createApiSourceset
204    project.ext.setApiModuleDependencies = this.&setApiModuleDependencies
205
206
207    version = rootProject.ext.supportVersion
208    group = 'com.android.support'
209
210    repositories {
211        maven { url "${project.parent.projectDir}/../../prebuilts/tools/common/m2/repository" }
212        maven { url "${project.parent.projectDir}/../../prebuilts/tools/common/m2/internal" }
213        maven { url "${project.parent.projectDir}/../../prebuilts/maven_repo/android" }
214    }
215
216    task release(type: Upload) {
217        configuration = configurations.archives
218        repositories {
219            mavenDeployer {
220                repository(url: uri("$rootProject.ext.supportRepoOut"))
221
222                // Disable unique names for SNAPSHOTS so they can be updated in place.
223                setUniqueVersion(false)
224                doLast {
225                    // Remove any invalid maven-metadata.xml files that may have been created
226                    // for SNAPSHOT versions that are *not* uniquely versioned.
227                    pom*.each { pom ->
228                        if (pom.version.endsWith('-SNAPSHOT')) {
229                            final File artifactDir = new File(rootProject.ext.supportRepoOut,
230                                    pom.groupId.replace('.', '/')
231                                    + '/' + pom.artifactId
232                                    + '/' + pom.version)
233                            delete fileTree(dir: artifactDir, include: 'maven-metadata.xml*')
234                        }
235                    }
236                }
237           }
238        }
239    }
240
241    def deployer = release.repositories.mavenDeployer
242    deployer.pom*.whenConfigured { pom ->
243        pom.dependencies.findAll {dep -> dep.groupId == 'com.android.support' && dep.artifactId != 'support-annotations' }*.type = 'aar'
244    }
245
246    // before the upload, make sure the repo is ready.
247    release.dependsOn rootProject.tasks.prepareRepo
248    // make the mainupload depend on this one.
249    mainUpload.dependsOn release
250
251    project.plugins.whenPluginAdded { plugin ->
252        if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
253            project.android.buildToolsVersion = rootProject.buildToolsVersion
254            // enable code coverage for debug builds only if we are not running inside the IDE
255            // enabling coverage reports breaks the method parameter resolution in the IDE debugger
256            project.android.buildTypes.debug.testCoverageEnabled = !hasProperty('android.injected.invoked.from.ide')
257        }
258    }
259
260    // Copy instrumentation test APK into the dist dir
261    project.afterEvaluate {
262        def assembleTestTask = project.tasks.findByPath('assembleAndroidTest')
263        if (assembleTestTask != null) {
264            assembleTestTask.doLast {
265                // If the project actually has some instrumentation tests, copy its APK
266                if (!project.android.sourceSets.androidTest.java.sourceFiles.isEmpty()) {
267                    def pkgTask = project.tasks.findByPath('packageDebugAndroidTest')
268                    copy {
269                        from(pkgTask.outputFile)
270                        into(rootProject.ext.testApkDistOut)
271                    }
272                }
273            }
274        }
275    }
276
277    project.afterEvaluate { p ->
278        // remove dependency on the test so that we still get coverage even if some tests fail
279        p.tasks.findAll { it instanceof JacocoReportTask}.each { task ->
280            def toBeRemoved = new ArrayList()
281            def dependencyList = task.taskDependencies.values
282            dependencyList.each { dep ->
283                if (dep instanceof String) {
284                    def t = tasks.findByName(dep)
285                    if (t instanceof DeviceProviderInstrumentTestTask) {
286                        toBeRemoved.add(dep)
287                        task.mustRunAfter(t)
288                    }
289                }
290            }
291            toBeRemoved.each { dep ->
292                dependencyList.remove(dep)
293            }
294        }
295    }
296}
297
298project.gradle.buildFinished { buildResult ->
299    if (buildResult.getFailure() != null) {
300        println()
301        println 'Build failed. Possible causes include:'
302        println '    1) Bad codes'
303        println '    2) Out of date prebuilts in prebuilts/sdk'
304        println '    3) Need to update the compileSdkVersion in a library\'s build.gradle'
305        println()
306    }
307}
308
309FileCollection getAndroidPrebuilt(String apiLevel) {
310    files("$rootDir/../../prebuilts/sdk/$apiLevel/android.jar")
311}
312