Skip to content

Commit b3a048f

Browse files
authored
Fix case-sensitivity of FS lookup (#84)
Fixes #76
1 parent b91b8e1 commit b3a048f

File tree

2 files changed

+27
-16
lines changed

2 files changed

+27
-16
lines changed

src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class BinaryCompatibilityValidatorPlugin : Plugin<Project> {
6464
it.description = "Task that collects all target specific dump tasks"
6565
}
6666

67-
val commonApiCheck: TaskProvider<Task>? = project.tasks.register("apiCheck") {
67+
val commonApiCheck: TaskProvider<Task> = project.tasks.register("apiCheck") {
6868
it.group = "verification"
6969
it.description = "Shortcut task that depends on all specific check tasks"
7070
}.apply { project.tasks.named("check") { it.dependsOn(this) } }
@@ -243,7 +243,7 @@ private fun Project.configureCheckTasks(
243243
logger.debug("Configuring api for ${targetConfig.targetName ?: "jvm"} to $r")
244244
}
245245
}
246-
val apiCheck = task<ApiCompareCompareTask>(targetConfig.apiTaskName("Check")) {
246+
val apiCheck = task<KotlinApiCompareTask>(targetConfig.apiTaskName("Check")) {
247247
isEnabled = apiCheckEnabled(extension) && apiBuild.map { it.enabled }.getOrElse(true)
248248
group = "verification"
249249
description = "Checks signatures of public API against the golden value in API folder for $projectName"

src/main/kotlin/ApiCompareCompareTask.kt renamed to src/main/kotlin/KotlinApiCompareTask.kt

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import org.gradle.api.file.*
1111
import org.gradle.api.model.ObjectFactory
1212
import org.gradle.api.tasks.*
1313
import java.io.*
14-
import java.util.TreeSet
14+
import java.util.TreeMap
1515
import javax.inject.Inject
1616

17-
open class ApiCompareCompareTask @Inject constructor(private val objects: ObjectFactory): DefaultTask() {
17+
open class KotlinApiCompareTask @Inject constructor(private val objects: ObjectFactory): DefaultTask() {
1818

1919
/*
2020
* Nullability and optionality is a workaround for
@@ -38,6 +38,7 @@ open class ApiCompareCompareTask @Inject constructor(private val objects: Object
3838

3939
@OutputFile
4040
@Optional
41+
@Suppress("unused")
4142
val dummyOutputFile: File? = null
4243

4344
private val projectName = project.name
@@ -47,38 +48,48 @@ open class ApiCompareCompareTask @Inject constructor(private val objects: Object
4748
@TaskAction
4849
fun verify() {
4950
val projectApiDir = projectApiDir
50-
if (projectApiDir == null) {
51-
error("Expected folder with API declarations '$nonExistingProjectApiDir' does not exist.\n" +
51+
?: error("Expected folder with API declarations '$nonExistingProjectApiDir' does not exist.\n" +
5252
"Please ensure that ':apiDump' was executed in order to get API dump to compare the build against")
53-
}
5453

5554
val subject = projectName
56-
val apiBuildDirFiles = mutableSetOf<RelativePath>()
57-
// We use case-insensitive comparison to workaround issues with case-insensitive OSes
58-
// and Gradle behaving slightly different on different platforms
59-
val expectedApiFiles = TreeSet<RelativePath> { rp, rp2 ->
55+
56+
/*
57+
* We use case-insensitive comparison to workaround issues with case-insensitive OSes
58+
* and Gradle behaving slightly different on different platforms.
59+
* We neither know original sensitivity of existing .api files, not
60+
* build ones, because projectName that is part of the path can have any sensitvity.
61+
* To workaround that, we replace paths we are looking for the same paths that
62+
* actually exist on FS.
63+
*/
64+
fun caseInsensitiveMap() = TreeMap<RelativePath, RelativePath> { rp, rp2 ->
6065
rp.toString().compareTo(rp2.toString(), true)
6166
}
67+
68+
val apiBuildDirFiles = caseInsensitiveMap()
69+
val expectedApiFiles = caseInsensitiveMap()
70+
6271
objects.fileTree().from(apiBuildDir).visit { file ->
63-
apiBuildDirFiles.add(file.relativePath)
72+
apiBuildDirFiles[file.relativePath] = file.relativePath
6473
}
6574
objects.fileTree().from(projectApiDir).visit { file ->
66-
expectedApiFiles.add(file.relativePath)
75+
expectedApiFiles[file.relativePath] = file.relativePath
6776
}
6877

6978
if (apiBuildDirFiles.size != 1) {
7079
error("Expected a single file $subject.api, but found: $expectedApiFiles")
7180
}
7281

73-
val expectedApiDeclaration = apiBuildDirFiles.single()
82+
var expectedApiDeclaration = apiBuildDirFiles.keys.single()
7483
if (expectedApiDeclaration !in expectedApiFiles) {
7584
error("File ${expectedApiDeclaration.lastName} is missing from ${projectApiDir.relativePath()}, please run " +
7685
":$subject:apiDump task to generate one")
7786
}
78-
87+
// Normalize case-sensitivity
88+
expectedApiDeclaration = expectedApiFiles.getValue(expectedApiDeclaration)
89+
val actualApiDeclaration = apiBuildDirFiles.getValue(expectedApiDeclaration)
7990
val diffSet = mutableSetOf<String>()
8091
val expectedFile = expectedApiDeclaration.getFile(projectApiDir)
81-
val actualFile = expectedApiDeclaration.getFile(apiBuildDir)
92+
val actualFile = actualApiDeclaration.getFile(apiBuildDir)
8293
val diff = compareFiles(expectedFile, actualFile)
8394
if (diff != null) diffSet.add(diff)
8495
if (diffSet.isNotEmpty()) {

0 commit comments

Comments
 (0)