Skip to content

Commit

Permalink
Support reading classes from resulting jar and allow configuring task…
Browse files Browse the repository at this point in the history
…s without registering extension
  • Loading branch information
ilya-g committed Sep 27, 2022
1 parent 7d29849 commit 4a51ffe
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 24 deletions.
21 changes: 9 additions & 12 deletions src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt
Expand Up @@ -179,7 +179,7 @@ private fun Project.configureKotlinCompilation(
val apiDirProvider = targetConfig.apiDir
val apiBuildDir = apiDirProvider.map { buildDir.resolve(it) }

val apiBuild = task<KotlinApiBuildTask>(targetConfig.apiTaskName("Build"), extension) {
val apiBuild = task<KotlinApiBuildTask>(targetConfig.apiTaskName("Build")) {
// Do not enable task for empty umbrella modules
isEnabled =
apiCheckEnabled(projectName, extension) && compilation.allKotlinSourceSets.any { it.kotlin.srcDirs.any { it.exists() } }
Expand All @@ -199,6 +199,9 @@ private fun Project.configureKotlinCompilation(
files(provider<Any> { if (isEnabled) compilation.compileDependencyFiles else emptyList<Any>() })
}
outputApiDir = apiBuildDir.get()
ignoredPackages = extension.ignoredPackages
ignoredClasses = extension.ignoredClasses
nonPublicMarkers = extension.nonPublicMarkers
}
configureCheckTasks(apiBuildDir, apiBuild, extension, targetConfig, commonApiDump, commonApiCheck)
}
Expand All @@ -216,14 +219,17 @@ private fun Project.configureApiTasks(
) {
val projectName = project.name
val apiBuildDir = targetConfig.apiDir.map { buildDir.resolve(it) }
val apiBuild = task<KotlinApiBuildTask>(targetConfig.apiTaskName("Build"), extension) {
val apiBuild = task<KotlinApiBuildTask>(targetConfig.apiTaskName("Build")) {
isEnabled = apiCheckEnabled(projectName, extension)
// 'group' is not specified deliberately so it will be hidden from ./gradlew tasks
description =
"Builds Kotlin API for 'main' compilations of $projectName. Complementary task and shouldn't be called manually"
inputClassesDirs = files(provider<Any> { if (isEnabled) sourceSet.output.classesDirs else emptyList<Any>() })
inputDependencies = files(provider<Any> { if (isEnabled) sourceSet.output.classesDirs else emptyList<Any>() })
outputApiDir = apiBuildDir.get()
ignoredPackages = extension.ignoredPackages
ignoredClasses = extension.ignoredClasses
nonPublicMarkers = extension.nonPublicMarkers
}

configureCheckTasks(apiBuildDir, apiBuild, extension, targetConfig)
Expand All @@ -247,16 +253,7 @@ private fun Project.configureCheckTasks(
isEnabled = apiCheckEnabled(projectName, extension) && apiBuild.map { it.enabled }.getOrElse(true)
group = "verification"
description = "Checks signatures of public API against the golden value in API folder for $projectName"
run {
val d = apiCheckDir.get()
projectApiDir = if (d.exists()) {
d
} else {
nonExistingProjectApiDir = d.toString()
null
}
this.apiBuildDir = apiBuildDir.get()
}
compareApiDumps(apiReferenceDir = apiCheckDir.get(), apiBuildDir = apiBuildDir.get())
dependsOn(apiBuild)
}

Expand Down
45 changes: 33 additions & 12 deletions src/main/kotlin/KotlinApiBuildTask.kt
Expand Up @@ -10,15 +10,21 @@ import org.gradle.api.*
import org.gradle.api.file.*
import org.gradle.api.tasks.*
import java.io.*
import java.util.jar.JarFile
import javax.inject.Inject

open class KotlinApiBuildTask @Inject constructor(
private val extension: ApiValidationExtension
) : DefaultTask() {

@InputFiles
@Optional
@PathSensitive(PathSensitivity.RELATIVE)
lateinit var inputClassesDirs: FileCollection
var inputClassesDirs: FileCollection? = null

@InputFile
@Optional
@PathSensitive(PathSensitivity.RELATIVE)
val inputJar: RegularFileProperty = this.project.objects.fileProperty()

@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
Expand All @@ -28,13 +34,13 @@ open class KotlinApiBuildTask @Inject constructor(
lateinit var outputApiDir: File

@get:Input
val ignoredPackages : Set<String> get() = extension.ignoredPackages
var ignoredPackages : Set<String> = emptySet()

@get:Input
val nonPublicMarkers : Set<String> get() = extension.nonPublicMarkers
var nonPublicMarkers : Set<String> = emptySet()

@get:Input
val ignoredClasses : Set<String> get() = extension.ignoredClasses
var ignoredClasses : Set<String> = emptySet()

@get:Internal
internal val projectName = project.name
Expand All @@ -44,17 +50,32 @@ open class KotlinApiBuildTask @Inject constructor(
cleanup(outputApiDir)
outputApiDir.mkdirs()

val signatures = inputClassesDirs.asFileTree.asSequence()
.filter {
!it.isDirectory && it.name.endsWith(".class") && !it.name.startsWith("META-INF/")
}
.map { it.inputStream() }
.loadApiFromJvmClasses()
val inputClassesDirs = inputClassesDirs
if (listOfNotNull(inputClassesDirs, inputJar.orNull).size != 1) {
throw GradleException("KotlinApiBuildTask should have either inputClassesDirs, or inputJar properties set")
}
val signatures = when {
inputClassesDirs != null ->
inputClassesDirs.asFileTree.asSequence()
.filter {
!it.isDirectory && it.name.endsWith(".class") && !it.name.startsWith("META-INF/")
}
.map { it.inputStream() }
.loadApiFromJvmClasses()
inputJar.isPresent ->
JarFile(inputJar.get().asFile)
.loadApiFromJvmClasses()
else ->
error("Unreachable")
}


val filteredSignatures = signatures
.filterOutNonPublic(ignoredPackages, ignoredClasses)
.filterOutAnnotated(nonPublicMarkers.map { it.replace(".", "/") }.toSet())

outputApiDir.resolve("$projectName.api").bufferedWriter().use { writer ->
signatures
filteredSignatures
.sortedBy { it.name }
.forEach { api ->
writer.append(api.signature).appendLine(" {")
Expand Down
10 changes: 10 additions & 0 deletions src/main/kotlin/KotlinApiCompareTask.kt
Expand Up @@ -32,6 +32,16 @@ open class KotlinApiCompareTask @Inject constructor(private val objects: ObjectF
@Optional
var nonExistingProjectApiDir: String? = null

fun compareApiDumps(apiReferenceDir: File, apiBuildDir: File) {
if (apiReferenceDir.exists()) {
projectApiDir = apiReferenceDir
} else {
projectApiDir = null
nonExistingProjectApiDir = apiReferenceDir.toString()
}
this.apiBuildDir = apiBuildDir
}

@InputDirectory
@PathSensitive(PathSensitivity.RELATIVE)
lateinit var apiBuildDir: File
Expand Down

0 comments on commit 4a51ffe

Please sign in to comment.