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

workaround bugged Gradle attributes #215

Merged
merged 3 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,34 @@ interface DokkatooAttribute {

/** HTML, Markdown, etc. */
@DokkatooInternalApi
interface Format : Named
@JvmInline
value class Format(private val named: String) : Named {
override fun getName(): String = named
}

/** Generated output, or subproject classpath, or included files, etc */
@DokkatooInternalApi
interface ModuleComponent : Named
@JvmInline
value class ModuleComponent(private val named: String) : Named {
override fun getName(): String = named
}

/** A classpath, e.g. for Dokka Plugins or the Dokka Generator. */
@DokkatooInternalApi
interface Classpath : Named
@JvmInline
value class Classpath(private val named: String) : Named {
override fun getName(): String = named
}

@DokkatooInternalApi
companion object {
val DokkatooFormatAttribute: Attribute<Format> =
val DokkatooFormatAttribute: Attribute<String> =
Attribute("dev.adamko.dokkatoo.format")

val DokkatooModuleComponentAttribute: Attribute<ModuleComponent> =
val DokkatooModuleComponentAttribute: Attribute<String> =
Attribute("dev.adamko.dokkatoo.module-component")

val DokkatooClasspathAttribute: Attribute<Classpath> =
val DokkatooClasspathAttribute: Attribute<String> =
Attribute("dev.adamko.dokkatoo.classpath")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class FormatDependenciesManager(
internal val formatAttributes: FormatAttributes =
FormatAttributes(
formatName = formatName,
objects = objects,
)

init {
Expand Down Expand Up @@ -94,8 +93,8 @@ class FormatDependenciesManager(
isTransitive = false
attributes {
jvmJar()
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaPlugins)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaPlugins.name)
}
}
//endregion
Expand All @@ -117,8 +116,8 @@ class FormatDependenciesManager(
extendsFrom(dokkaPublicationPluginClasspath.get())
attributes {
jvmJar()
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaPublicationPlugins)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaPublicationPlugins.name)
}
}

Expand All @@ -137,8 +136,8 @@ class FormatDependenciesManager(
extendsFrom(dokkaPublicationPluginClasspathApiOnly.get())
attributes {
jvmJar()
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaPublicationPlugins)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaPublicationPlugins.name)
}
}
}
Expand Down Expand Up @@ -186,8 +185,8 @@ class FormatDependenciesManager(

attributes {
jvmJar()
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaGenerator)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooClasspathAttribute, baseAttributes.dokkaGenerator.name)
}
}
//endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ class ModuleComponentDependencies(
extendsFrom(declaredDependencies)
attributes {
attribute(USAGE_ATTRIBUTE, baseAttributes.dokkatooUsage)
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooModuleComponentAttribute, component)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooModuleComponentAttribute, component.name)
}
}

Expand All @@ -46,8 +46,8 @@ class ModuleComponentDependencies(
extendsFrom(declaredDependencies)
attributes {
attribute(USAGE_ATTRIBUTE, baseAttributes.dokkatooUsage)
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooModuleComponentAttribute, component)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooModuleComponentAttribute, component.name)
}
}

Expand Down Expand Up @@ -83,8 +83,8 @@ class ModuleComponentDependencies(
withVariantReselection()
attributes {
attribute(USAGE_ATTRIBUTE, usage)
attribute(DokkatooFormatAttribute, formatAttributes.format)
attribute(DokkatooModuleComponentAttribute, component)
attribute(DokkatooFormatAttribute, formatAttributes.format.name)
attribute(DokkatooModuleComponentAttribute, component.name)
}
lenient(true)
}
Expand All @@ -98,23 +98,23 @@ class ModuleComponentDependencies(
.filter { artifact ->
val variantAttributes = artifact.variant.attributes
when {
artifact.variant.attributes[USAGE_ATTRIBUTE]?.name != baseAttributes.dokkatooUsage.name -> {
logger.info("[${incomingName}] ignoring artifact $artifact - USAGE_ATTRIBUTE != ${baseAttributes.dokkatooUsage} | attributes:${variantAttributes.toMap()}")
variantAttributes[USAGE_ATTRIBUTE]?.name != baseAttributes.dokkatooUsage.name -> {
logger.info("[${incomingName}] ignoring artifact $artifact - USAGE_ATTRIBUTE != ${baseAttributes.dokkatooUsage} | attributes:${variantAttributes.toDebugString()}")
false
}

variantAttributes[DokkatooFormatAttribute]?.name != formatAttributes.format.name -> {
logger.info("[${incomingName}] ignoring artifact $artifact - DokkatooFormatAttribute != ${formatAttributes.format} | attributes:${variantAttributes.toMap()}")
variantAttributes[DokkatooFormatAttribute] != formatAttributes.format.name -> {
logger.info("[${incomingName}] ignoring artifact $artifact - DokkatooFormatAttribute != ${formatAttributes.format} | attributes:${variantAttributes.toDebugString()}")
false
}

variantAttributes[DokkatooModuleComponentAttribute]?.name != component.name -> {
logger.info("[${incomingName}] ignoring artifact $artifact - DokkatooModuleComponentAttribute != $component | attributes:${variantAttributes.toMap()}")
variantAttributes[DokkatooModuleComponentAttribute] != component.name -> {
logger.info("[${incomingName}] ignoring artifact $artifact - DokkatooModuleComponentAttribute != $component | attributes:${variantAttributes.toDebugString()}")
false
}

else -> {
logger.info("[${incomingName}] found valid artifact $artifact | attributes:${variantAttributes.toMap()}")
else -> {
logger.info("[${incomingName}] found valid artifact $artifact | attributes:${variantAttributes.toDebugString()}")
true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,26 @@ class BaseAttributes(
objects: ObjectFactory,
) {
val dokkatooUsage: Usage = objects.named("dev.adamko.dokkatoo")
val dokkaPlugins: DokkatooAttribute.Classpath = objects.named("dokka-plugins")

val dokkaPlugins: DokkatooAttribute.Classpath =
DokkatooAttribute.Classpath("dokka-plugins")

val dokkaPublicationPlugins: DokkatooAttribute.Classpath =
objects.named("dokka-publication-plugins")
val dokkaGenerator: DokkatooAttribute.Classpath = objects.named("dokka-generator")
DokkatooAttribute.Classpath("dokka-publication-plugins")

val dokkaGenerator: DokkatooAttribute.Classpath =
DokkatooAttribute.Classpath("dokka-generator")
}


/** [Attribute] values for a specific Dokka format. */
@DokkatooInternalApi
class FormatAttributes(
formatName: String,
objects: ObjectFactory,
) {
val format: DokkatooAttribute.Format = objects.named(formatName)
val format: DokkatooAttribute.Format =
DokkatooAttribute.Format(formatName)

val moduleOutputDirectories: DokkatooAttribute.ModuleComponent =
objects.named("ModuleOutputDirectories")
DokkatooAttribute.ModuleComponent("ModuleOutputDirectories")
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,13 @@ abstract class DokkatooFormatPlugin(
dokkatooExtension.versions.jetbrainsDokka.map { version -> create("org.jetbrains.dokka:$module:$version") }

private fun AttributeContainer.dokkaPluginsClasspath() {
attribute(DokkatooFormatAttribute, formatDependencies.formatAttributes.format)
attribute(DokkatooClasspathAttribute, formatDependencies.baseAttributes.dokkaPlugins)
attribute(DokkatooFormatAttribute, formatDependencies.formatAttributes.format.name)
attribute(DokkatooClasspathAttribute, formatDependencies.baseAttributes.dokkaPlugins.name)
}

private fun AttributeContainer.dokkaGeneratorClasspath() {
attribute(DokkatooFormatAttribute, formatDependencies.formatAttributes.format)
attribute(DokkatooClasspathAttribute, formatDependencies.baseAttributes.dokkaGenerator)
attribute(DokkatooFormatAttribute, formatDependencies.formatAttributes.format.name)
attribute(DokkatooClasspathAttribute, formatDependencies.baseAttributes.dokkaGenerator.name)
}

/** Add a dependency to the Dokka plugins classpath */
Expand Down
72 changes: 67 additions & 5 deletions modules/dokkatoo-plugin/src/main/kotlin/internal/gradleUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -237,16 +237,33 @@ internal fun ObjectFactory.dokkaPluginParametersContainer(): DokkaPluginParamete


/**
* Creates a new attribute of the given name with the given type.
* Creates a new [Attribute] of the given name with the given type [T].
*
* @see Attribute.of
*/
@Deprecated(
"Typed attributes are broken - use String attributes instead. https://github.com/adamko-dev/dokkatoo/issues/214",
ReplaceWith("dev.adamko.dokkatoo.internal.Attribute(name)"),
)
@JvmName("TypedAttribute")
internal inline fun <reified T> Attribute(
name: String
): Attribute<T> =
Attribute.of(name, T::class.java)


/**
* Creates a new [Attribute] of the given name with a type of [String].
*
* @see Attribute.of
*/
@JvmName("StringAttribute")
internal fun Attribute(
name: String
): Attribute<String> =
Attribute.of(name, String::class.java)


internal val ArtifactTypeAttribute: Attribute<String> = Attribute("artifactType")


Expand All @@ -262,14 +279,59 @@ internal fun AttributeContainer.toMap(): Map<Attribute<*>, Any?> =
keySet().associateWith { getAttribute(it) }


internal fun AttributeContainer.toDebugString(): String =
toMap().entries.joinToString { (k, v) -> "$k[name:${k.name}, type:${k.type}, type.hc:${k.type.hashCode()}]=$v" }


/**
* Get an [Attribute] from an [AttributeContainer].
*
* (Nicer Kotlin accessor function).
*/
internal operator fun <T : Any> AttributeContainer.get(key: Attribute<T>): T? =
getAttribute(key)
internal operator fun <T : Any> AttributeContainer.get(key: Attribute<T>): T? {
// first, try the official way
val value = getAttribute(key)
if (value != null) {
return value
}

// Failed to get attribute using official method, which might have been caused by a Gradle bug
// https://github.com/gradle/gradle/issues/28695
// Attempting to check...

internal infix fun <T> Attribute<T>?.eq(other: Attribute<T>) =
this?.name == other.name
// Quickly check that any attribute has the same name.
// (There's no point in checking further if no names match.)
if (keySet().none { it.name == key.name }) {
return null
}

val actualKey = keySet()
.firstOrNull { candidate -> candidate.matchesTypeOf(key) }
?: return null

error(
"""
Gradle failed to fetch attribute from AttributeContainer, even though the attribute is present.
Please report this error to Gradle https://github.com/gradle/gradle/issues/28695
Requested attribute: $key ${key.type} ${key.type.hashCode()}
Actual attribute: $actualKey ${actualKey.type} ${actualKey.type.hashCode()}
All attributes: ${toDebugString()}
Gradle Version: $CurrentGradleVersion
""".trimIndent()
)
}

/** Leniently check if [Attribute.type]s are equal, avoiding [Class.hashCode] classloader differences. */
private fun Attribute<*>.matchesTypeOf(other: Attribute<*>): Boolean {
val thisTypeId = this.typeId() ?: false
val otherTypeId = other.typeId() ?: false
return thisTypeId == otherTypeId
}

/**
* An ID for [Attribute.type] that is stable across different classloaders.
*
* Workaround for https://github.com/gradle/gradle/issues/28695.
*/
private fun Attribute<*>.typeId(): String? =
type.toString().ifBlank { null }