1/* 2 * Copyright (C) 2017 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 17 18import androidx.build.DiffAndDocs 19import androidx.build.PublishDocsRulesKt 20import androidx.build.gmaven.GMavenVersionChecker 21import androidx.build.license.CheckExternalDependencyLicensesTask 22import com.android.build.gradle.internal.coverage.JacocoReportTask 23import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask 24import org.gradle.api.logging.configuration.ShowStacktrace 25 26import javax.tools.ToolProvider 27 28def supportRoot = ext.supportRootFolder 29if (supportRoot == null) { 30 throw new RuntimeException("variable supportRootFolder is not set. you must set it before" + 31 " including this script") 32} 33def init = new Properties() 34ext.init = init 35rootProject.ext.versionChecker = new GMavenVersionChecker(rootProject.logger) 36ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null 37 38apply from: "${supportRoot}/buildSrc/dependencies.gradle" 39apply from: "${supportRoot}/buildSrc/build_dependencies.gradle" 40apply from: "${supportRoot}/buildSrc/unbundled_check.gradle" 41 42 43def enableDoclavaAndJDiff(p, dacOptions, rules = []) { 44 p.configurations { 45 doclava 46 jdiff 47 } 48 49 p.dependencies { 50 doclava build_libs.doclava 51 // tools.jar required for com.sun.javadoc 52 doclava files(((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs()) 53 jdiff build_libs.jdiff 54 jdiff build_libs.xml_parser_apis 55 jdiff build_libs.xerces_impl 56 } 57 58 return DiffAndDocs.configureDiffAndDocs(rootProject, supportRootFolder, 59 dacOptions, rules) 60} 61 62def getFullSdkPath() { 63 if (isUnbundledBuild(ext.supportRootFolder)) { 64 Properties properties = new Properties() 65 File propertiesFile = new File('local.properties') 66 if (propertiesFile.exists()) { 67 propertiesFile.withInputStream { 68 properties.load(it) 69 } 70 } 71 File location = findSdkLocation(properties, supportRootFolder) 72 return location.getAbsolutePath() 73 } else { 74 final String osName = System.getProperty("os.name").toLowerCase(); 75 final boolean isMacOsX = 76 osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx"); 77 final String platform = isMacOsX ? 'darwin' : 'linux' 78 return "${repos.prebuiltsRoot}/fullsdk-${platform}" 79 } 80} 81 82/** 83 * Adapted from com.android.build.gradle.internal.SdkHandler 84 */ 85public static File findSdkLocation(Properties properties, File rootDir) { 86 String sdkDirProp = properties.getProperty("sdk.dir"); 87 if (sdkDirProp != null) { 88 File sdk = new File(sdkDirProp); 89 if (!sdk.isAbsolute()) { 90 sdk = new File(rootDir, sdkDirProp); 91 } 92 return sdk 93 } 94 95 sdkDirProp = properties.getProperty("android.dir"); 96 if (sdkDirProp != null) { 97 return new File(rootDir, sdkDirProp); 98 } 99 100 String envVar = System.getenv("ANDROID_HOME"); 101 if (envVar != null) { 102 return new File(envVar); 103 } 104 105 String property = System.getProperty("android.home"); 106 if (property != null) { 107 return new File(property); 108 } 109 return null; 110} 111 112def setSdkInLocalPropertiesFile() { 113 final File fullSdkPath = file(getFullSdkPath()) 114 if (fullSdkPath.exists()) { 115 project.ext.fullSdkPath = fullSdkPath 116 File props = file("local.properties") 117 props.write "sdk.dir=${fullSdkPath.getAbsolutePath()}" 118 ext.usingFullSdk = true 119 } else { 120 throw Exception("You are using non ub-supportlib-* checkout. You need to check out " 121 + "ub-supportlib-* to work on support library. See go/supportlib for details.") 122 } 123} 124 125def setupRepoOutAndBuildNumber() { 126 // common support repo folder which works well for prebuilts. 127 ext.supportRepoOut = '' 128 ext.buildNumber = "0" 129 /* 130 * With the build server you are given two env variables. 131 * The OUT_DIR is a temporary directory you can use to put things during the build. 132 * The DIST_DIR is where you want to save things from the build. 133 * 134 * The build server will copy the contents of DIST_DIR to somewhere and make it available. 135 */ 136 if (ext.runningInBuildServer) { 137 buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build') 138 .getCanonicalFile() 139 project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile() 140 141 // the build server does not pass the build number so we infer it from the last folder of 142 // the dist path. 143 ext.buildNumber = project.ext.distDir.getName() 144 145 // the build server should always print out full stack traces for any failures. 146 gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS 147 } else { 148 buildDir = file("${ext.supportRootFolder}/../../out/host/gradle/frameworks/support/build") 149 project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist") 150 } 151 subprojects { 152 // Change buildDir first so that all plugins pick up the new value. 153 project.buildDir = new File("$project.parent.buildDir/../$project.name/build") 154 } 155 ext.supportRepoOut = new File(buildDir, 'support_repo') 156 ext.testApkDistOut = ext.distDir 157 ext.testResultsDistDir = new File(distDir, "host-test-reports") 158 ext.docsDir = new File(buildDir, 'javadoc') 159} 160 161def configureBuildOnServer() { 162 def buildOnServerTask = rootProject.tasks.create("buildOnServer") 163 rootProject.tasks.whenTaskAdded { task -> 164 if ("createArchive".equals(task.name) 165 || "createDiffArchive".equals(task.name) 166 || "distDocs".equals(task.name) 167 || "dejetifyArchive".equals(task.name) 168 || CheckExternalDependencyLicensesTask.ROOT_TASK_NAME.equals(task.name)) { 169 buildOnServerTask.dependsOn task 170 } 171 } 172 def docsProject = rootProject.findProject(":docs-fake") 173 subprojects { 174 if (docsProject == project) { 175 return 176 } 177 project.tasks.whenTaskAdded { task -> 178 if ("assembleErrorProne".equals(task.name) 179 || "assembleAndroidTest".equals(task.name) 180 || "assembleDebug".equals(task.name)) { 181 buildOnServerTask.dependsOn task 182 } 183 } 184 } 185 buildOnServerTask.dependsOn createJacocoAntUberJarTask() 186 return buildOnServerTask 187} 188 189def createJacocoAntUberJarTask() { 190 def myJacoco = project.configurations.create('myJacoco') 191 project.dependencies.add('myJacoco', build_libs.jacoco_ant) 192 193 return project.tasks.create( 194 name: "JacocoAntUberJar", 195 type: Jar) { 196 inputs.files myJacoco 197 from { 198 myJacoco 199 .resolvedConfiguration 200 .resolvedArtifacts.collect{ zipTree(it.getFile()) }} { 201 // exclude all the signatures the jar might have 202 exclude "META-INF/*.SF" 203 exclude "META-INF/*.DSA" 204 exclude "META-INF/*.RSA" 205 } 206 destinationDir file(project.distDir) 207 archiveName "jacocoant.jar" 208 } 209} 210 211def configureSubProjects() { 212 subprojects { 213 repos.addMavenRepositories(repositories) 214 215 // Only modify Android projects. 216 if (project.name.equals('noto-emoji-compat')) { 217 // disable tests and return 218 project.tasks.whenTaskAdded { task -> 219 if (task instanceof org.gradle.api.tasks.testing.Test) { 220 task.enabled = false 221 } 222 } 223 return 224 } 225 226 project.plugins.whenPluginAdded { plugin -> 227 def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin" 228 .equals(plugin.class.name) 229 def isAndroidApp = "com.android.build.gradle.AppPlugin".equals(plugin.class.name) 230 231 if (isAndroidLibrary || isAndroidApp) { 232 // Enable code coverage for debug builds only if we are not running inside the IDE, 233 // since enabling coverage reports breaks the method parameter resolution in the IDE 234 // debugger. 235 project.android.buildTypes.debug.testCoverageEnabled = 236 !project.hasProperty('android.injected.invoked.from.ide') 237 238 // Copy the class files in a jar to be later used to generate code coverage report 239 project.android.testVariants.all { v -> 240 // check if the variant has any source files 241 // and test coverage is enabled 242 if (v.buildType.testCoverageEnabled 243 && v.sourceSets.any { !it.java.sourceFiles.isEmpty() }) { 244 def jarifyTask = project.tasks.create( 245 name: "package${v.name.capitalize()}ClassFilesForCoverageReport", 246 type: Jar) { 247 from v.testedVariant.javaCompile.destinationDir 248 exclude "**/R.class" 249 exclude "**/R\$*.class" 250 exclude "**/BuildConfig.class" 251 destinationDir file(project.distDir) 252 archiveName "${project.name}-${v.baseName}-allclasses.jar" 253 } 254 255 jarifyTask.dependsOn v.getJavaCompiler() 256 v.assemble.dependsOn jarifyTask 257 } 258 } 259 } 260 } 261 262 // Copy instrumentation test APKs and app APKs into the dist dir 263 // For test apks, they are uploaded only if we have java test sources. 264 // For regular app apks, they are uploaded only if they have java sources. 265 project.tasks.whenTaskAdded { task -> 266 if (task.name.startsWith("packageDebug")) { 267 def testApk = task.name.contains("AndroidTest") 268 task.doLast { 269 def source = testApk ? project.android.sourceSets.androidTest 270 : project.android.sourceSets.main 271 def hasKotlinSources = false 272 if (source.hasProperty('kotlin')) { 273 if (!source.kotlin.files.isEmpty()) { 274 hasKotlinSources = true 275 } else { 276 // kotlin files does not show in java sources due to the *.java filter 277 // so we need to check them manually 278 hasKotlinSources = source.java.sourceDirectoryTrees.any { 279 !fileTree(dir: it.dir, include:'**/*.kt').files.isEmpty() 280 } 281 } 282 } 283 def hasSourceCode = !source.java.sourceFiles.isEmpty() || hasKotlinSources 284 if (task.hasProperty("outputDirectory") && (hasSourceCode || !testApk)) { 285 copy { 286 from(task.outputDirectory) 287 include '*.apk' 288 into(rootProject.ext.testApkDistOut) 289 rename { String fileName -> 290 // Exclude media-compat-test-* modules from existing support library 291 // presubmit tests. 292 if (fileName.contains("media-compat-test")) { 293 fileName.replace("-debug-androidTest", "") 294 } else { 295 // multiple modules may have the same name so prefix the name with 296 // the module's path to ensure it is unique. 297 // e.g. palette-v7-debug-androidTest.apk becomes 298 // support-palette-v7_palette-v7-debug-androidTest.apk 299 "${project.getPath().replace(':', '-').substring(1)}_${fileName}" 300 } 301 } 302 } 303 } 304 } 305 } 306 } 307 308 // copy host side test results to DIST 309 project.tasks.whenTaskAdded { task -> 310 if (task instanceof org.gradle.api.tasks.testing.Test) { 311 def junitReport = task.reports.junitXml 312 if (junitReport.enabled) { 313 def zipTask = project.tasks.create(name : "zipResultsOf${task.name.capitalize()}", type : Zip) { 314 destinationDir(testResultsDistDir) 315 // first one is always :, drop it. 316 archiveName("${project.getPath().split(":").join("_").substring(1)}.zip") 317 } 318 if (project.rootProject.ext.runningInBuildServer) { 319 task.ignoreFailures = true 320 } 321 task.finalizedBy zipTask 322 task.doFirst { 323 zipTask.from(junitReport.destination) 324 } 325 } 326 } 327 } 328 329 project.afterEvaluate { p -> 330 // remove dependency on the test so that we still get coverage even if some tests fail 331 p.tasks.findAll { it instanceof JacocoReportTask }.each { task -> 332 def toBeRemoved = new ArrayList() 333 def dependencyList = task.taskDependencies.values 334 dependencyList.each { dep -> 335 if (dep instanceof String) { 336 def t = tasks.findByName(dep) 337 if (t instanceof DeviceProviderInstrumentTestTask) { 338 toBeRemoved.add(dep) 339 task.mustRunAfter(t) 340 } 341 } 342 } 343 toBeRemoved.each { dep -> 344 dependencyList.remove(dep) 345 } 346 } 347 } 348 } 349} 350 351def setupRelease() { 352 apply from: "${ext.supportRootFolder}/buildSrc/release.gradle" 353} 354 355ext.init.enableDoclavaAndJDiff = this.&enableDoclavaAndJDiff 356ext.init.setSdkInLocalPropertiesFile = this.&setSdkInLocalPropertiesFile 357ext.init.setupRepoOutAndBuildNumber = this.&setupRepoOutAndBuildNumber 358ext.init.setupRelease = this.&setupRelease 359ext.init.configureSubProjects = this.&configureSubProjects 360ext.init.configureBuildOnServer = this.&configureBuildOnServer 361