Skip to content

Commit

Permalink
Generate an adhoc sw component
Browse files Browse the repository at this point in the history
  • Loading branch information
John Engelman authored and Goooler committed Sep 13, 2024
1 parent 83aa1c7 commit 413f5e3
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 143 deletions.
4 changes: 2 additions & 2 deletions src/docs/publishing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ apply plugin: 'com.gradleup.shadow'
publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
shadow(MavenPublication) {
components.shadow
}
}
repositories {
Expand Down
Original file line number Diff line number Diff line change
@@ -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> archive
private final Provider<List<Dep>> 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<RegularFile> file
Property<String> classifier

Archive(Provider<RegularFile> file, Property<String> 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"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -19,39 +21,41 @@ class ShadowJavaPlugin implements Plugin<Project> {
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 {
Expand All @@ -68,9 +72,9 @@ class ShadowJavaPlugin implements Plugin<Project> {
}
}

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")
Expand All @@ -91,6 +95,7 @@ class ShadowJavaPlugin implements Plugin<Project> {
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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class PublishingSpec extends PluginSpecification {
publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
shadow(MavenPublication) {
from components.shadow
artifactId = 'maven-all'
}
}
Expand Down Expand Up @@ -196,8 +196,8 @@ class PublishingSpec extends PluginSpecification {
publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
shadow(MavenPublication) {
from components.shadow
artifactId = 'maven-all'
}
}
Expand Down Expand Up @@ -255,6 +255,10 @@ class PublishingSpec extends PluginSpecification {
java(MavenPublication) {
from components.java
}
shadow(MavenPublication) {
from components.shadow
artifactId = "maven-all"
}
}
repositories {
maven {
Expand All @@ -267,59 +271,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
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down

0 comments on commit 413f5e3

Please sign in to comment.