blob: 553cdf2767288d4c00a8ce5faee20c35a4a70c1b [file] [log] [blame]
/*
* Copyright (C) 2019 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.
*/
package com.android.build.gradle.internal.scope
import com.android.builder.core.LibraryRequest
import com.android.builder.errors.IssueReporter
import com.android.sdklib.AndroidVersion
import com.android.sdklib.OptionalLibrary
import com.google.common.base.Verify
import com.google.common.collect.ImmutableList
import java.io.File
import java.util.Objects
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import java.util.concurrent.ConcurrentHashMap
/** Utility methods for computing class paths to use for compilation. */
object BootClasspathBuilder {
private data class CacheKey(val target: AndroidVersion, val addAllOptionalLibraries: Boolean, val libraryRequests: List<LibraryRequest>)
private val classpathCache = ConcurrentHashMap<CacheKey, List<File>>()
/**
* Computes the classpath for compilation.
*
* @param project target project
* @param issueReporter sync issue reporter to report missing optional libraries with.
* @param target the lazy provider for sdk information
* @param annotationsJar the lazy provider for annotations jar file.
* @param addAllOptionalLibraries true if all optional libraries should be included.
* @param libraryRequests list of optional libraries to find and include.
* @return a classpath as a [FileCollection]
*/
fun computeClasspath(
project: Project,
issueReporter: IssueReporter,
targetBootClasspath: Provider<List<File>>,
targetAndroidVersion: Provider<AndroidVersion>,
additionalLibraries: Provider<List<OptionalLibrary>>,
optionalLibraries: Provider<List<OptionalLibrary>>,
annotationsJar: Provider<File>,
addAllOptionalLibraries: Boolean,
libraryRequests: List<LibraryRequest>
): FileCollection {
return project.files(
targetBootClasspath.map { bootClasspath ->
val target = targetAndroidVersion.get()
val key = CacheKey(target, addAllOptionalLibraries, libraryRequests)
classpathCache.getOrPut(key) {
val files = ImmutableList.builder<File>()
files.addAll(bootClasspath)
// add additional and requested optional libraries if any
files.addAll(
computeAdditionalAndRequestedOptionalLibraries(
additionalLibraries.get(), optionalLibraries.get(), addAllOptionalLibraries, libraryRequests, issueReporter
)
)
// add annotations.jar if needed.
if (target.apiLevel <= 15) {
files.add(annotationsJar.get())
}
files.build()
}
})
}
/**
* Calculates the list of additional and requested optional library jar files
*
* @param androidTarget the Android Target
* @param addAllOptionalLibraries overrides {@code libraryRequestsArg} and add all optional
* libraries available.
* @param libraryRequestsArg the list of requested optional libraries
* @param issueReporter the issueReporter which is written to if a requested library is not
* found
* @return a list of File to add to the classpath.
*/
fun computeAdditionalAndRequestedOptionalLibraries(
additionalLibraries: List<OptionalLibrary>,
optionalLibraries: List<OptionalLibrary>,
addAllOptionalLibraries: Boolean,
libraryRequestsArg: List<LibraryRequest>,
issueReporter: IssueReporter
): List<File> {
// iterate through additional libraries first, in case they contain
// a requested library
val libraryRequests = libraryRequestsArg.map { it.name }.toMutableSet()
val files = ImmutableList.builder<File>()
additionalLibraries
.stream()
.map<File> { lib ->
val jar = lib.jar
Verify.verify(
jar != null,
"Jar missing from additional library %s.",
lib.name
)
// search if requested, and remove from libraryRequests if so
if (libraryRequests.contains(lib.name)) {
libraryRequests.remove(lib.name)
}
jar
}
.filter { Objects.nonNull(it) }
.forEach { files.add(it) }
// then iterate through optional libraries
optionalLibraries
.stream()
.map<File> { lib ->
// add to jar and remove from requests
val libraryRequested = libraryRequests.contains(lib.name)
if (addAllOptionalLibraries || libraryRequested) {
val jar = lib.jar
Verify.verify(
jar != null,
"Jar missing from optional library %s.",
lib.name
)
if (libraryRequested) {
libraryRequests.remove(lib.name)
}
jar
} else {
null
}
}
.filter { Objects.nonNull(it) }
.forEach { files.add(it) }
// look for not found requested libraries.
for (library in libraryRequests) {
issueReporter.reportError(
IssueReporter.Type.OPTIONAL_LIB_NOT_FOUND,
"Unable to find optional library: $library",
library)
}
return files.build()
}
}