Skip to content

Commit

Permalink
feat: allow to exclude ABI by source path
Browse files Browse the repository at this point in the history
  • Loading branch information
Vampire committed Jul 9, 2024
1 parent 4c6085d commit f7e5f4d
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 11 deletions.
7 changes: 3 additions & 4 deletions src/main/kotlin/com/autonomousapps/extension/AbiHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ abstract class ExclusionsHandler @Inject constructor(objects: ObjectFactory) {
annotationExclusions.addAll(*annotationRegexes)
}

// TODO Excluded for now but left as a toe-hold for future use
// fun excludePaths(@Language("RegExp") vararg pathRegexes: String) {
// pathExclusions.addAll(*pathRegexes)
// }
fun excludePaths(@Language("RegExp") vararg pathRegexes: String) {
pathExclusions.addAll(*pathRegexes)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ internal class AndroidLibAnalyzer(
if (!hasAbi) return null

return project.tasks.register<AbiAnalysisTask>("abiAnalysis$taskNameSuffix") {
sourceFiles.setFrom(javaSourceFiles)
sourceFiles.setFrom(kotlinSourceFiles)
sourceFiles.setFrom(groovySourceFiles)
sourceFiles.setFrom(scalaSourceFiles)
exclusions.set(abiExclusions)
output.set(outputPaths.abiAnalysisPath)
abiDump.set(outputPaths.abiDumpPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ internal abstract class JvmAnalyzer(
if (!hasAbi) return null

return project.tasks.register<AbiAnalysisTask>("abiAnalysis$variantNameCapitalized") {
sourceFiles.setFrom(sourceSet.sourceCode)
classes.setFrom(sourceSet.classesDirs)
exclusions.set(abiExclusions)
output.set(outputPaths.abiAnalysisPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ internal fun JarFile.classEntries() = Sequence { entries().iterator() }.filter {
}

internal fun getBinaryAPI(jar: JarFile, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> =
getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityFilter)
getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityFilter = visibilityFilter)

internal fun getBinaryAPI(classes: Set<File>, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> =
getBinaryAPI(classes.asSequence().map { it.inputStream() }, visibilityFilter)
internal fun getBinaryAPI(classes: Set<File>, sourceFiles: Set<File>, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> =
getBinaryAPI(classes.asSequence().map { it.inputStream() }, sourceFiles, visibilityFilter)

internal fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> {
internal fun getBinaryAPI(classStreams: Sequence<InputStream>, sourceFiles: Set<File> = emptySet(), visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> {
val classNodes = classStreams.map {
it.use { stream ->
val classNode = ClassNode()
Expand All @@ -53,6 +53,10 @@ internal fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityFilter:

val visibilityMapNew = classNodes.readKotlinVisibilities().filterKeys(visibilityFilter)

val sourceFilePackageReversedBySourceFile = sourceFiles.associateWith {
it.parentFile.invariantSeparatorsPath.split('/').reversed()
}

return classNodes
.filter { it != moduleInfo }
.map { clazz ->
Expand Down Expand Up @@ -112,6 +116,21 @@ internal fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityFilter:
// Strip out JDK classes
.filterNotToSet { it.startsWith("Ljava/lang") }

val sourceFileName = clazz.sourceFile ?: "${clazz.name.substringAfterLast('/')}."
val clazzPackageReversed = clazz.name.substringBeforeLast('/').split('/').reversed()
val sourceFile = sourceFilePackageReversedBySourceFile
.filterKeys { it.name.startsWith(sourceFileName) }
.maxByOrNull { (_, sourceFilePackageReversed) ->
sourceFilePackageReversed
.asSequence()
.zip(clazzPackageReversed.asSequence())
.takeWhile { (sourceFilePart, clazzPart) -> sourceFilePart == clazzPart }
.count()
}
?.key
?.invariantSeparatorsPath
?: sourceFileName

ClassBinarySignature(
name = name,
superName = superName,
Expand All @@ -124,7 +143,7 @@ internal fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityFilter:
isNotUsedWhenEmpty = metadata.isFileOrMultipartFacade() || isDefaultImpls(metadata),
annotations = visibleAnnotations.annotationTypes(),
invisibleAnnotations = invisibleAnnotations.annotationTypes(),
sourceFile = clazz.sourceFile
sourceFile = sourceFile
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import java.util.jar.JarFile

internal fun computeAbi(
classFiles: Set<File>,
sourceFiles: Set<File>,
exclusions: AbiExclusions,
abiDumpFile: File? = null
): Set<ExplodingAbi> = getBinaryAPI(classFiles).explodedAbi(exclusions, abiDumpFile)
): Set<ExplodingAbi> = getBinaryAPI(classFiles, sourceFiles).explodedAbi(exclusions, abiDumpFile)

private fun List<ClassBinarySignature>.explodedAbi(
exclusions: AbiExclusions,
Expand Down
10 changes: 9 additions & 1 deletion src/main/kotlin/com/autonomousapps/tasks/AbiAnalysisTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ abstract class AbiAnalysisTask @Inject constructor(
description = "Produces a report of the ABI of this project"
}

/** Source files from which the class files were generated. May be empty. */
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection

/** Class files generated by any JVM source (Java, Kotlin, Groovy, etc.). May be empty. */
@get:Classpath
@get:InputFiles
Expand All @@ -48,6 +53,7 @@ abstract class AbiAnalysisTask @Inject constructor(
@TaskAction
fun action() {
workerExecutor.noIsolation().submit(AbiAnalysisWorkAction::class.java) {
sourceFiles.setFrom(this@AbiAnalysisTask.sourceFiles.asFileTree)
// JVM projects
classFiles.setFrom(classes.asFileTree.filterToClassFiles().files)
// Android projects
Expand All @@ -60,6 +66,7 @@ abstract class AbiAnalysisTask @Inject constructor(
}

interface AbiAnalysisParameters : WorkParameters {
val sourceFiles: ConfigurableFileCollection
val classFiles: ConfigurableFileCollection
val exclusions: Property<String>
val output: RegularFileProperty
Expand All @@ -72,10 +79,11 @@ abstract class AbiAnalysisTask @Inject constructor(
val output = parameters.output.getAndDelete()
val outputAbiDump = parameters.abiDump.getAndDelete()

val sourceFiles = parameters.sourceFiles.files
val classFiles = parameters.classFiles.files
val exclusions = parameters.exclusions.orNull?.fromJson<AbiExclusions>() ?: AbiExclusions.NONE

val explodingAbi = computeAbi(classFiles, exclusions, outputAbiDump)
val explodingAbi = computeAbi(classFiles, sourceFiles, exclusions, outputAbiDump)

output.bufferWriteJsonSet(explodingAbi)
}
Expand Down

0 comments on commit f7e5f4d

Please sign in to comment.