1 /*
<lambda>null2 * Copyright (C) 2023 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 // Integration test project that analyzes an external dependency: see libraryToRunAgainst.
18 // Set INTEGRATION=true to enable.
19
20 import com.android.build.api.attributes.BuildTypeAttr
21
22 plugins {
23 id("com.android.library") // needed for bootClasspath and AAR transforms to work
24 }
25
<lambda>null26 repositories {
27 google()
28 mavenCentral()
29 }
30
31 // Create two configurations used in dependencies {} block.
32 val runner: Configuration by configurations.creating
<lambda>null33 val libraryToRunAgainst: Configuration by configurations.creating {
34 isCanBeResolved = false
35 isCanBeConsumed = false
36 }
37
<lambda>null38 dependencies {
39 libraryToRunAgainst("androidx.compose.foundation:foundation:1.4.3")
40 runner(project(":metalava"))
41 }
42
<lambda>null43 android { // minimal set up to make com.android.library plugin work
44 compileSdkVersion = "android-33"
45 namespace = "com.android.tools.metalava.integration"
46 }
47
48 /**
49 * Configuration used to resolve source jars for projects in libraryToRunAgainst
50 */
<lambda>null51 val sources: Configuration by configurations.creating {
52 extendsFrom(libraryToRunAgainst)
53 attributes {
54 attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
55 attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION))
56 attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.SOURCES))
57 attribute(
58 LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
59 project.objects.named(LibraryElements.JAR)
60 )
61 }
62 }
63
Configurationnull64 fun Configuration.setResolveClasspathForUsage(usage: String) {
65 isCanBeConsumed = false
66 attributes {
67 attribute(Usage.USAGE_ATTRIBUTE, project.objects.named<Usage>(usage))
68 attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named<Category>(Category.LIBRARY))
69 attribute(BuildTypeAttr.ATTRIBUTE, project.objects.named<BuildTypeAttr>("release"))
70 }
71 extendsFrom(sources)
72 }
73
74 /**
75 * Configuration used to resolve compile classpath for projects in libraryToRunAgainst
76 */
<lambda>null77 val sourcesCompileClasspath: Configuration by configurations.creating {
78 setResolveClasspathForUsage(Usage.JAVA_API)
79 }
80 /**
81 * Configuration used to resolve runtime classpath for projects in libraryToRunAgainst
82 */
<lambda>null83 val sourcesRuntimeClasspath: Configuration by configurations.creating {
84 setResolveClasspathForUsage(Usage.JAVA_RUNTIME)
85 }
86 /**
87 * Full classpath of all the dependencies needed to analyze projects in libraryToRunAgainst
88 * This includes android.jar, compile and runtime jars
89 */
90 val sourceDependencyClasspath: FileCollection = files(android.bootClasspath) +
<lambda>null91 sourcesCompileClasspath.incoming.artifactView {
92 attributes {
93 attribute(Attribute.of("artifactType", String::class.java), "android-classes")
94 }
95 }.files + sourcesRuntimeClasspath.incoming.artifactView {
<lambda>null96 attributes {
97 attribute(Attribute.of("artifactType", String::class.java), "android-classes")
98 }
99 }.files
100
101 @CacheableTask
102 abstract class MetalavaRunner : DefaultTask() {
103 @get:Inject
104 abstract val execOperations: ExecOperations
105 @get:[InputFiles PathSensitive(PathSensitivity.NONE)]
106 abstract var sources: File
107 @get:[InputFile PathSensitive(PathSensitivity.NONE)]
108 abstract val apiLintBaseline: RegularFileProperty
109 @get:Classpath
110 abstract val dependencyClasspath: ConfigurableFileCollection
111 @get:Classpath
112 abstract val metalavaClasspath: ConfigurableFileCollection
113 @get:OutputFile
114 abstract val signatureFile: RegularFileProperty
115
116 @TaskAction
doThingsnull117 fun doThings() {
118 // An approximation of AndroidX usage of metalava for tracking public
119 // api surface of a library and running API lint against it.
120 execOperations.javaexec {
121 mainClass.set("com.android.tools.metalava.Driver")
122 classpath = metalavaClasspath
123 args = listOf(
124 "--source-path",
125 sources.absolutePath,
126 "--api",
127 signatureFile.get().asFile.absolutePath,
128 "--classpath",
129 dependencyClasspath.files.joinToString(File.pathSeparator),
130 "--hide-annotation",
131 "androidx.annotation.RestrictTo",
132 "--show-unannotated",
133 "--api-lint",
134 "--baseline",
135 apiLintBaseline.get().asFile.absolutePath,
136 "--hide",
137 listOf(
138 "Enum",
139 "StartWithLower",
140 "MissingJvmstatic",
141 "ArrayReturn",
142 "UserHandleName",
143 ).joinToString(),
144 )
145 }
146 }
147 }
148
149 interface Injected {
150 @get:Inject val archiveOperations: ArchiveOperations
151 }
152
153 /**
154 * A task that will extract all of the source jars that are added to libraryToRunAgainst
155 * configuration.
156 */
<lambda>null157 val copyInputSources = tasks.register<Sync>("copyInputSources") {
158 // Store archiveOperations into a local variable to prevent access to project object
159 // during the task execution, as that breaks configuration caching.
160 val archiveOperations = project.objects.newInstance<Injected>().archiveOperations
161 from(
162 sources.incoming.artifactView { }.files.elements.map { jars ->
163 jars.map { jar ->
164 archiveOperations.zipTree(jar)
165 }
166 }
167 )
168 into(layout.buildDirectory.dir("inputSources"))
169 }
170
<lambda>null171 tasks.register<MetalavaRunner>("run") {
172 dependsOn(copyInputSources)
173 sources = copyInputSources.get().destinationDir
174 dependencyClasspath.from(sourceDependencyClasspath)
175 metalavaClasspath.from(runner)
176 signatureFile.set(layout.buildDirectory.file("current.txt"))
177 apiLintBaseline.set(layout.projectDirectory.file("api_lint.ignore"))
178 outputs.upToDateWhen { false }
179 }
180