Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support reading classes from resulting jar #99

Merged
merged 5 commits into from Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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")) {
qwwdfsad marked this conversation as resolved.
Show resolved Hide resolved
// 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
ilya-g marked this conversation as resolved.
Show resolved Hide resolved
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) {
qwwdfsad marked this conversation as resolved.
Show resolved Hide resolved
if (apiReferenceDir.exists()) {
projectApiDir = apiReferenceDir
} else {
projectApiDir = null
nonExistingProjectApiDir = apiReferenceDir.toString()
}
this.apiBuildDir = apiBuildDir
}

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