/* * Copyright (C) 2017 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. */ import androidx.build.DiffAndDocs import androidx.build.PublishDocsRulesKt import androidx.build.gmaven.GMavenVersionChecker import androidx.build.license.CheckExternalDependencyLicensesTask import com.android.build.gradle.internal.coverage.JacocoReportTask import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask import org.gradle.api.logging.configuration.ShowStacktrace import javax.tools.ToolProvider def supportRoot = ext.supportRootFolder if (supportRoot == null) { throw new RuntimeException("variable supportRootFolder is not set. you must set it before" + " including this script") } def init = new Properties() ext.init = init rootProject.ext.versionChecker = new GMavenVersionChecker(rootProject.logger) ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null apply from: "${supportRoot}/buildSrc/dependencies.gradle" apply from: "${supportRoot}/buildSrc/build_dependencies.gradle" apply from: "${supportRoot}/buildSrc/unbundled_check.gradle" def enableDoclavaAndJDiff(p, dacOptions, rules = []) { p.configurations { doclava jdiff } p.dependencies { doclava build_libs.doclava // tools.jar required for com.sun.javadoc doclava files(((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs()) jdiff build_libs.jdiff jdiff build_libs.xml_parser_apis jdiff build_libs.xerces_impl } return DiffAndDocs.configureDiffAndDocs(rootProject, supportRootFolder, dacOptions, rules) } def getFullSdkPath() { if (isUnbundledBuild(ext.supportRootFolder)) { Properties properties = new Properties() File propertiesFile = new File('local.properties') if (propertiesFile.exists()) { propertiesFile.withInputStream { properties.load(it) } } File location = findSdkLocation(properties, supportRootFolder) return location.getAbsolutePath() } else { final String osName = System.getProperty("os.name").toLowerCase(); final boolean isMacOsX = osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx"); final String platform = isMacOsX ? 'darwin' : 'linux' return "${repos.prebuiltsRoot}/fullsdk-${platform}" } } /** * Adapted from com.android.build.gradle.internal.SdkHandler */ public static File findSdkLocation(Properties properties, File rootDir) { String sdkDirProp = properties.getProperty("sdk.dir"); if (sdkDirProp != null) { File sdk = new File(sdkDirProp); if (!sdk.isAbsolute()) { sdk = new File(rootDir, sdkDirProp); } return sdk } sdkDirProp = properties.getProperty("android.dir"); if (sdkDirProp != null) { return new File(rootDir, sdkDirProp); } String envVar = System.getenv("ANDROID_HOME"); if (envVar != null) { return new File(envVar); } String property = System.getProperty("android.home"); if (property != null) { return new File(property); } return null; } def setSdkInLocalPropertiesFile() { final File fullSdkPath = file(getFullSdkPath()) if (fullSdkPath.exists()) { project.ext.fullSdkPath = fullSdkPath File props = file("local.properties") props.write "sdk.dir=${fullSdkPath.getAbsolutePath()}" ext.usingFullSdk = true } else { throw Exception("You are using non ub-supportlib-* checkout. You need to check out " + "ub-supportlib-* to work on support library. See go/supportlib for details.") } } def setupRepoOutAndBuildNumber() { // common support repo folder which works well for prebuilts. ext.supportRepoOut = '' ext.buildNumber = "0" /* * With the build server you are given two env variables. * The OUT_DIR is a temporary directory you can use to put things during the build. * The DIST_DIR is where you want to save things from the build. * * The build server will copy the contents of DIST_DIR to somewhere and make it available. */ if (ext.runningInBuildServer) { buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build') .getCanonicalFile() project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile() // the build server does not pass the build number so we infer it from the last folder of // the dist path. ext.buildNumber = project.ext.distDir.getName() // the build server should always print out full stack traces for any failures. gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS } else { buildDir = file("${ext.supportRootFolder}/../../out/host/gradle/frameworks/support/build") project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist") } subprojects { // Change buildDir first so that all plugins pick up the new value. project.buildDir = new File("$project.parent.buildDir/../$project.name/build") } ext.supportRepoOut = new File(buildDir, 'support_repo') ext.testApkDistOut = ext.distDir ext.testResultsDistDir = new File(distDir, "host-test-reports") ext.docsDir = new File(buildDir, 'javadoc') } def configureBuildOnServer() { def buildOnServerTask = rootProject.tasks.create("buildOnServer") rootProject.tasks.whenTaskAdded { task -> if ("createArchive".equals(task.name) || "createDiffArchive".equals(task.name) || "distDocs".equals(task.name) || "dejetifyArchive".equals(task.name) || CheckExternalDependencyLicensesTask.ROOT_TASK_NAME.equals(task.name)) { buildOnServerTask.dependsOn task } } def docsProject = rootProject.findProject(":docs-fake") subprojects { if (docsProject == project) { return } project.tasks.whenTaskAdded { task -> if ("assembleErrorProne".equals(task.name) || "assembleAndroidTest".equals(task.name) || "assembleDebug".equals(task.name)) { buildOnServerTask.dependsOn task } } } buildOnServerTask.dependsOn createJacocoAntUberJarTask() return buildOnServerTask } def createJacocoAntUberJarTask() { def myJacoco = project.configurations.create('myJacoco') project.dependencies.add('myJacoco', build_libs.jacoco_ant) return project.tasks.create( name: "JacocoAntUberJar", type: Jar) { inputs.files myJacoco from { myJacoco .resolvedConfiguration .resolvedArtifacts.collect{ zipTree(it.getFile()) }} { // exclude all the signatures the jar might have exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" } destinationDir file(project.distDir) archiveName "jacocoant.jar" } } def configureSubProjects() { subprojects { repos.addMavenRepositories(repositories) // Only modify Android projects. if (project.name.equals('noto-emoji-compat')) { // disable tests and return project.tasks.whenTaskAdded { task -> if (task instanceof org.gradle.api.tasks.testing.Test) { task.enabled = false } } return } project.plugins.whenPluginAdded { plugin -> def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin" .equals(plugin.class.name) def isAndroidApp = "com.android.build.gradle.AppPlugin".equals(plugin.class.name) if (isAndroidLibrary || isAndroidApp) { // Enable code coverage for debug builds only if we are not running inside the IDE, // since enabling coverage reports breaks the method parameter resolution in the IDE // debugger. project.android.buildTypes.debug.testCoverageEnabled = !project.hasProperty('android.injected.invoked.from.ide') // Copy the class files in a jar to be later used to generate code coverage report project.android.testVariants.all { v -> // check if the variant has any source files // and test coverage is enabled if (v.buildType.testCoverageEnabled && v.sourceSets.any { !it.java.sourceFiles.isEmpty() }) { def jarifyTask = project.tasks.create( name: "package${v.name.capitalize()}ClassFilesForCoverageReport", type: Jar) { from v.testedVariant.javaCompile.destinationDir exclude "**/R.class" exclude "**/R\$*.class" exclude "**/BuildConfig.class" destinationDir file(project.distDir) archiveName "${project.name}-${v.baseName}-allclasses.jar" } jarifyTask.dependsOn v.getJavaCompiler() v.assemble.dependsOn jarifyTask } } } } // Copy instrumentation test APKs and app APKs into the dist dir // For test apks, they are uploaded only if we have java test sources. // For regular app apks, they are uploaded only if they have java sources. project.tasks.whenTaskAdded { task -> if (task.name.startsWith("packageDebug")) { def testApk = task.name.contains("AndroidTest") task.doLast { def source = testApk ? project.android.sourceSets.androidTest : project.android.sourceSets.main def hasKotlinSources = false if (source.hasProperty('kotlin')) { if (!source.kotlin.files.isEmpty()) { hasKotlinSources = true } else { // kotlin files does not show in java sources due to the *.java filter // so we need to check them manually hasKotlinSources = source.java.sourceDirectoryTrees.any { !fileTree(dir: it.dir, include:'**/*.kt').files.isEmpty() } } } def hasSourceCode = !source.java.sourceFiles.isEmpty() || hasKotlinSources if (task.hasProperty("outputDirectory") && (hasSourceCode || !testApk)) { copy { from(task.outputDirectory) include '*.apk' into(rootProject.ext.testApkDistOut) rename { String fileName -> // Exclude media-compat-test-* modules from existing support library // presubmit tests. if (fileName.contains("media-compat-test")) { fileName.replace("-debug-androidTest", "") } else { // multiple modules may have the same name so prefix the name with // the module's path to ensure it is unique. // e.g. palette-v7-debug-androidTest.apk becomes // support-palette-v7_palette-v7-debug-androidTest.apk "${project.getPath().replace(':', '-').substring(1)}_${fileName}" } } } } } } } // copy host side test results to DIST project.tasks.whenTaskAdded { task -> if (task instanceof org.gradle.api.tasks.testing.Test) { def junitReport = task.reports.junitXml if (junitReport.enabled) { def zipTask = project.tasks.create(name : "zipResultsOf${task.name.capitalize()}", type : Zip) { destinationDir(testResultsDistDir) // first one is always :, drop it. archiveName("${project.getPath().split(":").join("_").substring(1)}.zip") } if (project.rootProject.ext.runningInBuildServer) { task.ignoreFailures = true } task.finalizedBy zipTask task.doFirst { zipTask.from(junitReport.destination) } } } } project.afterEvaluate { p -> // remove dependency on the test so that we still get coverage even if some tests fail p.tasks.findAll { it instanceof JacocoReportTask }.each { task -> def toBeRemoved = new ArrayList() def dependencyList = task.taskDependencies.values dependencyList.each { dep -> if (dep instanceof String) { def t = tasks.findByName(dep) if (t instanceof DeviceProviderInstrumentTestTask) { toBeRemoved.add(dep) task.mustRunAfter(t) } } } toBeRemoved.each { dep -> dependencyList.remove(dep) } } } } } def setupRelease() { apply from: "${ext.supportRootFolder}/buildSrc/release.gradle" } ext.init.enableDoclavaAndJDiff = this.&enableDoclavaAndJDiff ext.init.setSdkInLocalPropertiesFile = this.&setSdkInLocalPropertiesFile ext.init.setupRepoOutAndBuildNumber = this.&setupRepoOutAndBuildNumber ext.init.setupRelease = this.&setupRelease ext.init.configureSubProjects = this.&configureSubProjects ext.init.configureBuildOnServer = this.&configureBuildOnServer