-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hack attributes to workaround Gradle bugs (#173)
* Hack attributes to workaround Gradle bugs Also, remove unused 'incoming' Configuration * fixup! Hack attributes to workaround Gradle bugs * fixup! Hack attributes to workaround Gradle bugs * fixup! Hack attributes to workaround Gradle bugs * fixup! Hack attributes to workaround Gradle bugs
- Loading branch information
Showing
5 changed files
with
210 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
modules/dokkatoo-plugin/src/main/kotlin/dependencies/attributesHack.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package dev.adamko.dokkatoo.dependencies | ||
|
||
import org.gradle.api.Named | ||
import org.gradle.api.attributes.* | ||
import org.gradle.api.attributes.Bundling.BUNDLING_ATTRIBUTE | ||
import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE | ||
import org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE | ||
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE | ||
import org.gradle.api.attributes.java.TargetJvmEnvironment | ||
import org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE | ||
import org.gradle.kotlin.dsl.* | ||
|
||
/** | ||
* Dumb hack to work around Gradle bugs/issues/deficiencies. | ||
* | ||
* Basically, even though a [Configuration][org.gradle.api.artifacts.Configuration] might specify | ||
* some [Attribute]s, Gradle can, in some situations, randomly ignore them, leading to | ||
* files leaking between Configurations unexpectedly. This is a particular problem with JARs. | ||
* Dokkatoo needs to both resolve JARs from Maven Central, and also provide JARs to other | ||
* subprojects. | ||
* | ||
* To work around this: | ||
* | ||
* 1. When requesting or providing attributes, Dokkatoo adds a prefix ([AttributeHackPrefix]) to | ||
* the JAR specific Attribute values. | ||
* 2. When Dokkatoo shares files, the prefix prevents Gradle from getting confused with other | ||
* Configurations with similar Attributes. | ||
* 3. Dokkatoo adds some [AttributeCompatibilityRule]s for the JAR attributes, so that Dokkatoo | ||
* can ignore the prefix when **consuming**. | ||
*/ | ||
internal abstract class AttributeHackCompatibilityRule<T : Named> : AttributeCompatibilityRule<T> { | ||
override fun execute(details: CompatibilityCheckDetails<T>): Unit = details.run { | ||
val consumerName = consumerValue?.name?.substringAfter(AttributeHackPrefix) ?: return | ||
val producerName = producerValue?.name?.substringAfter(AttributeHackPrefix) ?: return | ||
if (consumerName == producerName) { | ||
compatible() | ||
} | ||
} | ||
} | ||
|
||
internal const val AttributeHackPrefix = "Dokkatoo~" | ||
|
||
internal class UsageHackRule : AttributeHackCompatibilityRule<Usage>() | ||
internal class CategoryHackRule : AttributeHackCompatibilityRule<Category>() | ||
internal class BundlingHackRule : AttributeHackCompatibilityRule<Bundling>() | ||
internal class TargetJvmEnvironmentHackRule : AttributeHackCompatibilityRule<TargetJvmEnvironment>() | ||
internal class LibraryElementsHackRule : AttributeHackCompatibilityRule<LibraryElements>() | ||
|
||
/** | ||
* @see AttributeHackCompatibilityRule | ||
*/ | ||
internal fun DependencyHandlerScope.applyAttributeHacks() { | ||
attributesSchema { | ||
attribute(USAGE_ATTRIBUTE) { | ||
compatibilityRules.add(UsageHackRule::class) | ||
} | ||
attribute(CATEGORY_ATTRIBUTE) { | ||
compatibilityRules.add(CategoryHackRule::class) | ||
} | ||
attribute(BUNDLING_ATTRIBUTE) { | ||
compatibilityRules.add(BundlingHackRule::class) | ||
} | ||
attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE) { | ||
compatibilityRules.add(TargetJvmEnvironmentHackRule::class) | ||
} | ||
attribute(LIBRARY_ELEMENTS_ATTRIBUTE) { | ||
compatibilityRules.add(LibraryElementsHackRule::class) | ||
} | ||
} | ||
} |
113 changes: 113 additions & 0 deletions
113
modules/dokkatoo-plugin/src/testFunctional/kotlin/AttributeHackTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package dev.adamko.dokkatoo | ||
|
||
import dev.adamko.dokkatoo.internal.DokkatooConstants | ||
import dev.adamko.dokkatoo.utils.* | ||
import io.kotest.core.spec.style.FunSpec | ||
|
||
|
||
class AttributeHackTest : FunSpec({ | ||
context("verify that Dokkatoo does not interfere with JAR Configurations") { | ||
|
||
val project = initProject() | ||
|
||
project.runner | ||
.addArguments( | ||
":subproject-without-dokkatoo:printJarFileCoords", | ||
"--quiet", | ||
"--stacktrace", | ||
"--no-configuration-cache", | ||
) | ||
.forwardOutput() | ||
.build { | ||
test("resolving JARs from a Dokkatoo-enabled project should not contain Dokka plugin JARs") { | ||
output.shouldNotContainAnyOf( | ||
"org.jetbrains.dokka", | ||
"all-modules-page-plugin", | ||
) | ||
} | ||
} | ||
} | ||
}) | ||
|
||
|
||
private fun initProject( | ||
config: GradleProjectTest.() -> Unit = {}, | ||
): GradleProjectTest { | ||
return gradleKtsProjectTest("attribute-hack-test") { | ||
|
||
settingsGradleKts += """ | ||
| | ||
|include(":subproject-with-dokkatoo") | ||
|include(":subproject-without-dokkatoo") | ||
| | ||
""".trimMargin() | ||
|
||
dir("subproject-with-dokkatoo") { | ||
buildGradleKts = """ | ||
|plugins { | ||
| kotlin("multiplatform") version embeddedKotlinVersion | ||
| id("dev.adamko.dokkatoo-html") version "${DokkatooConstants.DOKKATOO_VERSION}" | ||
|} | ||
| | ||
|kotlin { | ||
| jvm() | ||
|} | ||
""".trimMargin() | ||
} | ||
|
||
dir("subproject-without-dokkatoo") { | ||
|
||
buildGradleKts = """ | ||
|import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE | ||
|import org.gradle.api.attributes.Category.LIBRARY | ||
|import org.gradle.api.attributes.LibraryElements.JAR | ||
|import org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE | ||
|import org.gradle.api.attributes.Usage.JAVA_RUNTIME | ||
|import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE | ||
|import org.gradle.api.attributes.java.TargetJvmEnvironment.STANDARD_JVM | ||
|import org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE | ||
| | ||
|plugins { | ||
| `java-library` | ||
|} | ||
| | ||
|val jarFiles: Configuration by configurations.creating { | ||
| isCanBeResolved = false | ||
| isCanBeConsumed = false | ||
| isCanBeDeclared = true | ||
|} | ||
| | ||
|val jarFilesResolver: Configuration by configurations.creating { | ||
| isCanBeResolved = true | ||
| isCanBeConsumed = false | ||
| isCanBeDeclared = false | ||
| extendsFrom(jarFiles) | ||
| attributes { | ||
| //attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME)) | ||
| //attribute(CATEGORY_ATTRIBUTE, objects.named(LIBRARY)) | ||
| //attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named(STANDARD_JVM)) | ||
| //attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(JAR)) | ||
| //attribute(Attribute.of("org.jetbrains.kotlin.platform.type", String::class.java), "jvm") | ||
| } | ||
|} | ||
| | ||
|dependencies { | ||
| jarFiles(project(":subproject-with-dokkatoo")) | ||
|} | ||
| | ||
|val printJarFileCoords by tasks.registering { | ||
| val fileCoords = jarFilesResolver.incoming.artifacts.resolvedArtifacts.map { artifacts -> | ||
| artifacts.map { it.id.componentIdentifier.displayName } | ||
| } | ||
| inputs.files(jarFilesResolver).withPropertyName("jarFilesResolver") | ||
| doLast { | ||
| println(fileCoords.get().joinToString("\n")) | ||
| } | ||
|} | ||
| | ||
""".trimMargin() | ||
} | ||
|
||
config() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters