From e9348e43dd10310630c00cf463e7a26b4b0dbc2f Mon Sep 17 00:00:00 2001 From: John Engelman Date: Sun, 2 Apr 2023 04:37:24 +0800 Subject: [PATCH 1/2] Generate an adhoc sw component --- src/docs/publishing/README.md | 4 +- .../plugins/shadow/ShadowExtension.groovy | 71 ++------- .../plugins/shadow/ShadowJavaPlugin.groovy | 51 +++--- .../plugins/shadow/PublishingSpec.groovy | 149 +++++++++++------- .../shadow/util/PluginSpecification.groovy | 7 + 5 files changed, 139 insertions(+), 143 deletions(-) diff --git a/src/docs/publishing/README.md b/src/docs/publishing/README.md index 66da927f0..16c4fb400 100644 --- a/src/docs/publishing/README.md +++ b/src/docs/publishing/README.md @@ -15,8 +15,8 @@ apply plugin: 'com.gradleup.shadow' publishing { publications { - shadow(MavenPublication) { publication -> - project.shadow.component(publication) + shadow(MavenPublication) { + components.shadow } } repositories { diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy index 03a575d54..783ad928c 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy @@ -1,74 +1,23 @@ package com.github.jengelman.gradle.plugins.shadow -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.Project -import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.SelfResolvingDependency -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider -import org.gradle.api.publish.maven.MavenPom +import org.gradle.api.component.SoftwareComponentContainer import org.gradle.api.publish.maven.MavenPublication +@Deprecated class ShadowExtension { - private final Provider archive - private final Provider> allDependencies + private final SoftwareComponentContainer components ShadowExtension(Project project) { - archive = project.provider { - def archiveTask = project.tasks.withType(ShadowJar).getByName("shadowJar") - new Archive(archiveTask.archiveFile, archiveTask.archiveClassifier) - } - allDependencies = project.provider { - project.configurations.getByName("shadow").allDependencies.collect { - if ((it instanceof ProjectDependency) || !(it instanceof SelfResolvingDependency)) { - new Dep(it.group, it.name, it.version) - } - } - } + components = project.components } + /** + * @param publication + * @deprecated configure publication using component.shadow directly + */ + @Deprecated void component(MavenPublication publication) { - publication.artifact([ - source : archive.get().file, - classifier: archive.get().classifier.get() - ]) - - // Don't inline this variable, it seems Groovy closure capturing is confused by the field instead of a local variable. - final def allDeps = allDependencies - publication.pom { MavenPom pom -> - pom.withXml { xml -> - def dependenciesNode = xml.asNode().get('dependencies') ?: xml.asNode().appendNode('dependencies') - allDeps.get().each { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) - dependencyNode.appendNode('artifactId', it.name) - dependencyNode.appendNode('version', it.version) - dependencyNode.appendNode('scope', 'runtime') - } - } - } - } - - private class Archive { - Provider file - Property classifier - - Archive(Provider file, Property classifier) { - this.file = file - this.classifier = classifier - } - } - - private class Dep { - String group - String name - String version - - Dep(String group, String name, String version) { - this.group = group - this.name = name - this.version = version - } + publication.from(components.findByName("shadow")) } } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy index d3926974e..9b3aa99e4 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy @@ -8,6 +8,8 @@ import org.gradle.api.attributes.Category import org.gradle.api.attributes.LibraryElements import org.gradle.api.attributes.Usage import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.component.AdhocComponentWithVariants +import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.tasks.SourceSetContainer import org.gradle.configuration.project.ProjectConfigurationActionContainer import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin @@ -19,39 +21,41 @@ class ShadowJavaPlugin implements Plugin { public static final String SHADOW_JAR_TASK_NAME = 'shadowJar' public static final String SHADOW_GROUP = 'Shadow' - private final ProjectConfigurationActionContainer configurationActionContainer + private final SoftwareComponentFactory softwareComponentFactory @Inject - ShadowJavaPlugin(ProjectConfigurationActionContainer configurationActionContainer) { - this.configurationActionContainer = configurationActionContainer + ShadowJavaPlugin(SoftwareComponentFactory softwareComponentFactory) { + this.softwareComponentFactory = softwareComponentFactory } @Override void apply(Project project) { - configureShadowTask(project) + def shadowTask = configureShadowTask(project) project.configurations.compileClasspath.extendsFrom project.configurations.shadow - project.configurations { - shadowRuntimeElements { - canBeConsumed = true - canBeResolved = false - attributes { - it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, Usage.JAVA_RUNTIME)) - it.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category, Category.LIBRARY)) - it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR)) - it.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.SHADOWED)) - } - outgoing.artifact(project.tasks.named(SHADOW_JAR_TASK_NAME)) + project.configurations.register("shadowRuntimeElements") { + extendsFrom(project.configurations.shadow) + canBeResolved = false + canBeConsumed = true + attributes { + it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, Usage.JAVA_RUNTIME)) + it.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category, Category.LIBRARY)) + it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR)) + it.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.SHADOWED)) } + outgoing.artifact(shadowTask) } - project.configurations.shadowRuntimeElements.extendsFrom project.configurations.shadow + AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName("java") + javaComponent.addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + mapToOptional() + } - project.components.java { - addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { - mapToOptional() // make it a Maven optional dependency - } + AdhocComponentWithVariants shadow = softwareComponentFactory.adhoc("shadow") + project.components.add(shadow) + shadow.addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + mapToMavenScope("runtime") } project.plugins.withType(JavaGradlePluginPlugin).configureEach { @@ -68,9 +72,9 @@ class ShadowJavaPlugin implements Plugin { } } - protected static void configureShadowTask(Project project) { + protected static ShadowJar configureShadowTask(Project project) { SourceSetContainer sourceSets = project.extensions.getByType(SourceSetContainer) - project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar) { shadow -> + def taskProvider = project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar) { shadow -> shadow.group = SHADOW_GROUP shadow.description = 'Create a combined JAR of project and runtime dependencies' shadow.archiveClassifier.set("all") @@ -91,6 +95,7 @@ class ShadowJavaPlugin implements Plugin { project.configurations.runtimeClasspath : project.configurations.runtime] shadow.exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class') } - project.artifacts.add(ShadowBasePlugin.CONFIGURATION_NAME, project.tasks.named(SHADOW_JAR_TASK_NAME)) + project.artifacts.add(ShadowBasePlugin.CONFIGURATION_NAME, taskProvider.get()) + return taskProvider.get() } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy index 450f2a698..cbbb4fab7 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy @@ -41,8 +41,8 @@ class PublishingSpec extends PluginSpecification { publishing { publications { - shadow(MavenPublication) { publication -> - project.shadow.component(publication) + shadow(MavenPublication) { + from components.shadow artifactId = 'maven-all' } } @@ -191,8 +191,8 @@ class PublishingSpec extends PluginSpecification { publishing { publications { - shadow(MavenPublication) { publication -> - project.shadow.component(publication) + shadow(MavenPublication) { + from components.shadow artifactId = 'maven-all' } } @@ -250,6 +250,10 @@ class PublishingSpec extends PluginSpecification { java(MavenPublication) { from components.java } + shadow(MavenPublication) { + from components.shadow + artifactId = "maven-all" + } } repositories { maven { @@ -262,59 +266,90 @@ class PublishingSpec extends PluginSpecification { when: run('publish') - then: - File mainJar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.jar').canonicalFile - File shadowJar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0-all.jar').canonicalFile - assert mainJar.exists() - assert shadowJar.exists() - - and: - contains(shadowJar, ['a.properties', 'a2.properties']) - - and: "publishes both a POM file and a Gradle metadata file" - File pom = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.pom').canonicalFile - File gmm = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.module').canonicalFile - pom.exists() - gmm.exists() - - when: "POM file corresponds to a regular Java publication" - def pomContents = new XmlSlurper().parse(pom) - pomContents.dependencies.size() == 2 - - then: - def dependency1 = pomContents.dependencies[0].dependency[0] - dependency1.groupId.text() == 'shadow' - dependency1.artifactId.text() == 'a' - dependency1.version.text() == '1.0' - - def dependency2 = pomContents.dependencies[0].dependency[1] - dependency2.groupId.text() == 'shadow' - dependency2.artifactId.text() == 'b' - dependency2.version.text() == '1.0' - - when: "Gradle module metadata contains the Shadow variants" - def gmmContents = new JsonSlurper().parse(gmm) - - then: - gmmContents.variants.size() == 3 - gmmContents.variants.name as Set == ['apiElements', 'runtimeElements', 'shadowRuntimeElements'] as Set - - def apiVariant = gmmContents.variants.find { it.name == 'apiElements' } - apiVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_API - apiVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL - !apiVariant.dependencies - - def runtimeVariant = gmmContents.variants.find { it.name == 'runtimeElements' } - runtimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME - runtimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL - runtimeVariant.dependencies.size() == 2 - runtimeVariant.dependencies.module as Set == ['a', 'b'] as Set - - def shadowRuntimeVariant = gmmContents.variants.find { it.name == 'shadowRuntimeElements' } - shadowRuntimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME - shadowRuntimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.SHADOWED - shadowRuntimeVariant.dependencies.size() == 1 - shadowRuntimeVariant.dependencies.module as Set == ['b'] as Set + then: "verify java publication with shadow variant" + assertions { + File jar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.jar').canonicalFile + assert jar.exists() + } + assertions { + File jar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0-all.jar').canonicalFile + assert jar.exists() + contains(jar, ['a.properties', 'a2.properties']) + } + assertions { + File pom = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.pom').canonicalFile + assert pom.exists() + def pomContents = new XmlSlurper().parse(pom) + assert pomContents.dependencies[0].dependency.size() == 2 + + def dependency1 = pomContents.dependencies[0].dependency[0] + assert dependency1.groupId.text() == 'shadow' + assert dependency1.artifactId.text() == 'a' + assert dependency1.version.text() == '1.0' + + def dependency2 = pomContents.dependencies[0].dependency[1] + assert dependency2.groupId.text() == 'shadow' + assert dependency2.artifactId.text() == 'b' + assert dependency2.version.text() == '1.0' + } + + assertions { + File gmm = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.module').canonicalFile + assert gmm.exists() + def gmmContents = new JsonSlurper().parse(gmm) + assert gmmContents.variants.size() == 3 + assert gmmContents.variants.name as Set == ['apiElements', 'runtimeElements', 'shadowRuntimeElements'] as Set + + def apiVariant = gmmContents.variants.find { it.name == 'apiElements' } + assert apiVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_API + assert apiVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL + assert !apiVariant.dependencies + + def runtimeVariant = gmmContents.variants.find { it.name == 'runtimeElements' } + assert runtimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME + assert runtimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL + assert runtimeVariant.dependencies.size() == 2 + assert runtimeVariant.dependencies.module as Set == ['a', 'b'] as Set + + def shadowRuntimeVariant = gmmContents.variants.find { it.name == 'shadowRuntimeElements' } + assert shadowRuntimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME + assert shadowRuntimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.SHADOWED + assert shadowRuntimeVariant.dependencies.size() == 1 + assert shadowRuntimeVariant.dependencies.module as Set == ['b'] as Set + } + + and: "verify shadow publication" + assertions { + File jar = publishingRepo.rootDir.file('com/acme/maven-all/1.0/maven-all-1.0-all.jar').canonicalFile + assert jar.exists() + contains(jar, ['a.properties', 'a2.properties']) + } + + assertions { + File pom = publishingRepo.rootDir.file('com/acme/maven-all/1.0/maven-all-1.0.pom').canonicalFile + assert pom.exists() + def pomContents = new XmlSlurper().parse(pom) + assert pomContents.dependencies[0].dependency.size() == 1 + + def dependency1 = pomContents.dependencies[0].dependency[0] + assert dependency1.groupId.text() == 'shadow' + assert dependency1.artifactId.text() == 'b' + assert dependency1.version.text() == '1.0' + } + + assertions { + File gmm = publishingRepo.rootDir.file('com/acme/maven-all/1.0/maven-all-1.0.module').canonicalFile + assert gmm.exists() + def gmmContents = new JsonSlurper().parse(gmm) + assert gmmContents.variants.size() == 1 + assert gmmContents.variants.name as Set == ['shadowRuntimeElements'] as Set + + def runtimeVariant = gmmContents.variants.find { it.name == 'shadowRuntimeElements' } + assert runtimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME + assert runtimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.SHADOWED + assert runtimeVariant.dependencies.size() == 1 + assert runtimeVariant.dependencies.module as Set == ['b'] as Set + } } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index eb7ffa2fa..5dfde05a9 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -150,6 +150,13 @@ abstract class PluginSpecification extends Specification { jar.close() } + // Helper method to allow scoping variables into a closure in a spock test + // Prevents variable expansion + // When using this you *must* include explicit `assert` statements as Spock will not do it for you + void assertions(Closure closure) { + closure() + } + AppendableJar buildJar(String path) { return new AppendableJar(file(path)) } From 5ff401e075cb284963ecbfd589be5f93c20b11bf Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 13 Sep 2024 15:07:13 +0800 Subject: [PATCH 2/2] Cleanups --- .../gradle/plugins/shadow/ShadowJavaPlugin.groovy | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy index 9b3aa99e4..f34e4f137 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy @@ -11,7 +11,6 @@ import org.gradle.api.plugins.JavaPlugin import org.gradle.api.component.AdhocComponentWithVariants import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.tasks.SourceSetContainer -import org.gradle.configuration.project.ProjectConfigurationActionContainer import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin import javax.inject.Inject @@ -35,27 +34,27 @@ class ShadowJavaPlugin implements Plugin { project.configurations.compileClasspath.extendsFrom project.configurations.shadow project.configurations.register("shadowRuntimeElements") { - extendsFrom(project.configurations.shadow) - canBeResolved = false - canBeConsumed = true - attributes { + it.extendsFrom(project.configurations.shadow) + it.canBeConsumed = true + it.canBeResolved = false + it.attributes { it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, Usage.JAVA_RUNTIME)) it.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category, Category.LIBRARY)) it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR)) it.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.SHADOWED)) } - outgoing.artifact(shadowTask) + it.outgoing.artifact(shadowTask) } AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName("java") javaComponent.addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { - mapToOptional() + it.mapToOptional() } AdhocComponentWithVariants shadow = softwareComponentFactory.adhoc("shadow") project.components.add(shadow) shadow.addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { - mapToMavenScope("runtime") + it.mapToMavenScope("runtime") } project.plugins.withType(JavaGradlePluginPlugin).configureEach {