Repository: GradleUp/shadow
Pull request #1240 (2025-02-07 08:01:42)

Replace Jar attribute key hardcode


Patch:
diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.kt
index 74034b7b..daf9d3e7 100644
--- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.kt
+++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.kt
@@ -6,6 +6,7 @@ import com.github.jengelman.gradle.plugins.shadow.internal.applicationExtension
 import com.github.jengelman.gradle.plugins.shadow.internal.distributions
 import com.github.jengelman.gradle.plugins.shadow.internal.javaPluginExtension
 import com.github.jengelman.gradle.plugins.shadow.internal.javaToolchainService
+import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey
 import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsText
 import org.gradle.api.GradleException
 import org.gradle.api.Plugin
@@ -125,9 +126,9 @@ public abstract class ShadowApplicationPlugin : Plugin<Project> {
     tasks.shadowJar.configure { task ->
       task.inputs.property("mainClassName", mainClassName)
       task.doFirst {
-        // Inject the Main-Class attribute if it is not already present.
-        if (!task.manifest.attributes.contains("Main-Class")) {
-          task.manifest.attributes["Main-Class"] = mainClassName.get()
+        // Inject the attribute if it is not already present.
+        if (!task.manifest.attributes.contains(mainClassAttributeKey)) {
+          task.manifest.attributes[mainClassAttributeKey] = mainClassName.get()
         }
       }
     }
diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt
index 6cfd51db..4f147a3e 100644
--- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt
+++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt
@@ -1,6 +1,7 @@
 package com.github.jengelman.gradle.plugins.shadow
 
 import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin.Companion.shadow
+import com.github.jengelman.gradle.plugins.shadow.internal.classPathAttributeKey
 import com.github.jengelman.gradle.plugins.shadow.internal.jar
 import com.github.jengelman.gradle.plugins.shadow.internal.javaPluginExtension
 import com.github.jengelman.gradle.plugins.shadow.internal.runtimeConfiguration
@@ -43,12 +44,12 @@ public abstract class ShadowJavaPlugin @Inject constructor(
       task.archiveClassifier.set("all")
       @Suppress("EagerGradleConfiguration")
       task.manifest.inheritFrom(jarTask.get().manifest)
-      val attrProvider = jarTask.map { it.manifest.attributes["Class-Path"]?.toString().orEmpty() }
+      val attrProvider = jarTask.map { it.manifest.attributes[classPathAttributeKey]?.toString().orEmpty() }
       val files = files(configurations.shadow)
       task.doFirst {
         if (!files.isEmpty) {
           val attrs = listOf(attrProvider.getOrElse("")) + files.map { it.name }
-          task.manifest.attributes["Class-Path"] = attrs.joinToString(" ").trim()
+          task.manifest.attributes[classPathAttributeKey] = attrs.joinToString(" ").trim()
         }
       }
       task.from(sourceSets.named("main").map { it.output })
diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/Utils.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/Utils.kt
index b98ef3d6..ee62f471 100644
--- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/Utils.kt
+++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/Utils.kt
@@ -8,6 +8,7 @@ import java.nio.charset.Charset
 import java.nio.file.NoSuchFileException
 import java.nio.file.Path
 import java.util.Properties
+import java.util.jar.Attributes.Name as JarAttributeName
 import kotlin.io.path.inputStream
 import kotlin.io.path.toPath
 import org.gradle.api.file.RelativePath
@@ -16,6 +17,16 @@ import org.gradle.internal.file.Chmod
 import org.gradle.internal.file.FileMetadata
 import org.gradle.internal.file.Stat
 
+/**
+ * Known as `Main-Class` in the manifest file.
+ */
+internal val mainClassAttributeKey = JarAttributeName.MAIN_CLASS.toString()
+
+/**
+ * Known as `Class-Path` in the manifest file.
+ */
+internal val classPathAttributeKey = JarAttributeName.CLASS_PATH.toString()
+
 /**
  * This is used for creating a [DefaultFileTreeElement] with default values.
  * [file], [chmod], and [stat] should be non-null, so they are set to dummy values here.


Test patch:
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt
index 957beda5..e2f79e7f 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt
@@ -8,6 +8,8 @@ import assertk.assertions.doesNotContain
 import assertk.assertions.isEqualTo
 import com.github.jengelman.gradle.plugins.shadow.ShadowApplicationPlugin.Companion.SHADOW_INSTALL_TASK_NAME
 import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin.Companion.DISTRIBUTION_NAME
+import com.github.jengelman.gradle.plugins.shadow.internal.classPathAttributeKey
+import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey
 import com.github.jengelman.gradle.plugins.shadow.util.Issue
 import com.github.jengelman.gradle.plugins.shadow.util.JarPath
 import com.github.jengelman.gradle.plugins.shadow.util.containsEntries
@@ -117,7 +119,7 @@ class ApplicationPluginTest : BasePluginTest() {
       projectBlock = """
         shadowJar {
           manifest {
-            attributes 'Main-Class': 'shadow.Main2'
+            attributes '$mainClassAttributeKey': 'shadow.Main2'
           }
         }
       """.trimIndent(),
@@ -248,8 +250,8 @@ class ApplicationPluginTest : BasePluginTest() {
   ) {
     assertThat(jarPath).useAll {
       containsEntries(*entriesContained)
-      getMainAttr("Main-Class").isEqualTo(mainClassAttr)
-      getMainAttr("Class-Path").isEqualTo(classPathAttr)
+      getMainAttr(mainClassAttributeKey).isEqualTo(mainClassAttr)
+      getMainAttr(classPathAttributeKey).isEqualTo(classPathAttr)
     }
   }
 
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
index 998318b5..f4242c7f 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
@@ -10,6 +10,8 @@ import assertk.assertions.isNull
 import assertk.assertions.isTrue
 import assertk.assertions.single
 import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin.Companion.SHADOW_JAR_TASK_NAME
+import com.github.jengelman.gradle.plugins.shadow.internal.classPathAttributeKey
+import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey
 import com.github.jengelman.gradle.plugins.shadow.legacy.LegacyShadowPlugin
 import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
 import com.github.jengelman.gradle.plugins.shadow.util.BooleanParameterizedTest
@@ -362,7 +364,7 @@ class JavaPluginTest : BasePluginTest() {
 
     run(shadowJarTask)
 
-    val value = outputShadowJar.use { it.getMainAttr("Class-Path") }
+    val value = outputShadowJar.use { it.getMainAttr(classPathAttributeKey) }
     assertThat(value).isNull()
   }
 
@@ -378,7 +380,7 @@ class JavaPluginTest : BasePluginTest() {
         }
         jar {
           manifest {
-            attributes 'Class-Path': '/libs/a.jar'
+            attributes '$classPathAttributeKey': '/libs/a.jar'
           }
         }
       """.trimIndent(),
@@ -386,7 +388,7 @@ class JavaPluginTest : BasePluginTest() {
 
     run(shadowJarTask)
 
-    val value = outputShadowJar.use { it.getMainAttr("Class-Path") }
+    val value = outputShadowJar.use { it.getMainAttr(classPathAttributeKey) }
     assertThat(value).isEqualTo("/libs/a.jar junit-3.8.2.jar")
   }
 
@@ -405,7 +407,7 @@ class JavaPluginTest : BasePluginTest() {
 
     run(shadowJarTask)
 
-    val value = outputShadowJar.use { it.getMainAttr("Class-Path") }
+    val value = outputShadowJar.use { it.getMainAttr(classPathAttributeKey) }
     assertThat(value).isEqualTo("junit-3.8.2.jar")
   }
 
@@ -456,7 +458,7 @@ class JavaPluginTest : BasePluginTest() {
         .single().isEqualTo("my/plugin/MyPlugin.class")
       transform { it.manifest.mainAttributes }.isNotEmpty()
       // Doesn't contain Gradle classes.
-      getMainAttr("Class-Path").isNull()
+      getMainAttr(classPathAttributeKey).isNull()
 
       containsEntries(*entriesInA)
       doesNotContainEntries(*entriesInB)
@@ -482,7 +484,7 @@ class JavaPluginTest : BasePluginTest() {
           from sourceSets.test.output
           configurations = [project.configurations.testRuntimeClasspath]
           manifest {
-            attributes 'Main-Class': 'shadow.Main'
+            attributes '$mainClassAttributeKey': 'shadow.Main'
           }
         }
       """.trimIndent(),
@@ -496,7 +498,7 @@ class JavaPluginTest : BasePluginTest() {
         "junit/framework/Test.class",
         "shadow/Main.class",
       )
-      getMainAttr("Main-Class").isNotNull()
+      getMainAttr(mainClassAttributeKey).isNotNull()
     }
 
     val pathString = path("build/libs/shadow-1.0-tests.jar").toString()
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt
index 0dcaedb5..0e787c0c 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt
@@ -8,6 +8,7 @@ import assertk.assertions.isEmpty
 import assertk.assertions.isEqualTo
 import assertk.assertions.single
 import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin.Companion.SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME
+import com.github.jengelman.gradle.plugins.shadow.internal.classPathAttributeKey
 import com.github.jengelman.gradle.plugins.shadow.util.BooleanParameterizedTest
 import com.github.jengelman.gradle.plugins.shadow.util.GradleModuleMetadata
 import com.github.jengelman.gradle.plugins.shadow.util.Issue
@@ -454,7 +455,7 @@ class PublishingTest : BasePluginTest() {
     assertThat(jarPath).useAll {
       containsEntries(*entriesInA)
       doesNotContainEntries(*entriesInB)
-      getMainAttr("Class-Path").isEqualTo("b-1.0.jar")
+      getMainAttr(classPathAttributeKey).isEqualTo("b-1.0.jar")
     }
   }
 
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt
index 561f8c86..2ef72bdc 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt
@@ -6,6 +6,7 @@ import assertk.assertions.isEqualTo
 import assertk.assertions.isNotEqualTo
 import assertk.assertions.isNotNull
 import assertk.assertions.isNull
+import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey
 import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsText
 import com.github.jengelman.gradle.plugins.shadow.util.Issue
 import com.github.jengelman.gradle.plugins.shadow.util.containsEntries
@@ -27,8 +28,8 @@ class TransformersTest : BaseTransformerTest() {
       """
         jar {
           manifest {
-            attributes 'Main-Class': 'shadow.Main'
-            attributes 'Test-Entry': 'PASSED'
+            attributes '$mainClassAttributeKey': 'shadow.Main'
+            attributes '$TEST_ENTRY_ATTR_KEY': 'PASSED'
           }
         }
       """.trimIndent(),
@@ -37,8 +38,8 @@ class TransformersTest : BaseTransformerTest() {
     run(shadowJarTask)
 
     commonAssertions {
-      assertThat(getValue("Test-Entry")).isEqualTo("PASSED")
-      assertThat(getValue("Main-Class")).isEqualTo("shadow.Main")
+      assertThat(getValue(TEST_ENTRY_ATTR_KEY)).isEqualTo("PASSED")
+      assertThat(getValue(mainClassAttributeKey)).isEqualTo("shadow.Main")
     }
   }
 
@@ -67,9 +68,9 @@ class TransformersTest : BaseTransformerTest() {
 
     val mf = jarPath("build/libs/shadow-1.0.jar").use { it.manifest }
     assertThat(mf).isNotNull()
-    assertThat(mf.mainAttributes.getValue("Test-Entry")).isEqualTo("FAILED")
-    assertThat(mf.mainAttributes.getValue("Main-Class")).isEqualTo("shadow.Main")
-    assertThat(mf.mainAttributes.getValue("New-Entry")).isNull()
+    assertThat(mf.mainAttributes.getValue(TEST_ENTRY_ATTR_KEY)).isEqualTo("FAILED")
+    assertThat(mf.mainAttributes.getValue(mainClassAttributeKey)).isEqualTo("shadow.Main")
+    assertThat(mf.mainAttributes.getValue(NEW_ENTRY_ATTR_KEY)).isNull()
   }
 
   @Issue(
@@ -153,9 +154,9 @@ class TransformersTest : BaseTransformerTest() {
 
   private fun commonAssertions(
     mainAttributesBlock: Attributes.() -> Unit = {
-      assertThat(getValue("Test-Entry")).isEqualTo("PASSED")
-      assertThat(getValue("Main-Class")).isEqualTo("shadow.Main")
-      assertThat(getValue("New-Entry")).isEqualTo("NEW")
+      assertThat(getValue(TEST_ENTRY_ATTR_KEY)).isEqualTo("PASSED")
+      assertThat(getValue(mainClassAttributeKey)).isEqualTo("shadow.Main")
+      assertThat(getValue(NEW_ENTRY_ATTR_KEY)).isEqualTo("NEW")
     },
   ) {
     val mf = outputShadowJar.use { it.manifest }
@@ -164,17 +165,20 @@ class TransformersTest : BaseTransformerTest() {
   }
 
   private companion object {
+    const val NEW_ENTRY_ATTR_KEY = "New-Entry"
+    const val TEST_ENTRY_ATTR_KEY = "Test-Entry"
+
     val MANIFEST_ATTRS = """
         jar {
           manifest {
-            attributes 'Main-Class': 'shadow.Main'
-            attributes 'Test-Entry': 'FAILED'
+            attributes '$mainClassAttributeKey': 'shadow.Main'
+            attributes '$TEST_ENTRY_ATTR_KEY': 'FAILED'
           }
         }
         $shadowJar {
           manifest {
-            attributes 'New-Entry': 'NEW'
-            attributes 'Test-Entry': 'PASSED'
+            attributes '$NEW_ENTRY_ATTR_KEY': 'NEW'
+            attributes '$TEST_ENTRY_ATTR_KEY': 'PASSED'
           }
         }
     """.trimIndent()