-
-
Notifications
You must be signed in to change notification settings - Fork 420
Collision logging, Transformers for JSON and Standard Files #962
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
Closed
Master-Code-Programmer
wants to merge
15
commits into
GradleUp:main
from
Master-Code-Programmer:module-info_rebase
Closed
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
429fb3a
Displaying `warn` level messages when adding a file attempts to overw…
chapmajs 366ba52
Adding tests, not filtering META-INF/ by default
chapmajs bd44ee7
Cleaned up "Collision logging" and added StandardFilesMergeTransforme…
95338d0
Made StandardFilesMergeTransformer cacheable.
355c600
Displaying `warn` level messages when adding a file attempts to overw…
chapmajs 7224b29
Adding tests, not filtering META-INF/ by default
chapmajs 4449f35
Cleaned up "Collision logging" and added StandardFilesMergeTransforme…
3f06ef3
Fixed merge problems
5a5c759
Lower the log-level for duplicated "META-INF/MANIFEST.MF" from warn t…
125bad0
Adding JsonTransformer and tests for it
ff75169
Logging module-info.class collisions
77241f0
Fix rebase errors
cd41319
Added tests for StandardFilesMergeTransformer
3a1769b
Adding option allowModuleInfos() to make it optional to include modul…
8e62f66
Fixed rebase errors with module-info exclusion and moved dependencies
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
121 changes: 121 additions & 0 deletions
121
src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy
This file contains hidden or 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,121 @@ | ||
package com.github.jengelman.gradle.plugins.shadow | ||
|
||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar | ||
import org.gradle.api.Plugin | ||
import org.gradle.api.Project | ||
import org.gradle.api.artifacts.Configuration | ||
import org.gradle.api.attributes.Bundling | ||
import org.gradle.api.attributes.Category | ||
import org.gradle.api.attributes.LibraryElements | ||
import org.gradle.api.attributes.Usage | ||
import org.gradle.api.component.AdhocComponentWithVariants | ||
import org.gradle.api.component.SoftwareComponentFactory | ||
import org.gradle.api.plugins.JavaPlugin | ||
import org.gradle.api.tasks.SourceSetContainer | ||
import org.gradle.api.tasks.TaskProvider | ||
import org.gradle.jvm.tasks.Jar | ||
import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin | ||
|
||
import javax.inject.Inject | ||
|
||
class ShadowJavaPlugin implements Plugin<Project> { | ||
|
||
public static final String SHADOW_JAR_TASK_NAME = 'shadowJar' | ||
public static final String SHADOW_GROUP = 'Shadow' | ||
public static final String SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME = 'shadowRuntimeElements' | ||
|
||
public static final String MODULE_INFO_CLASS = 'module-info.class' | ||
|
||
private final SoftwareComponentFactory softwareComponentFactory | ||
|
||
@Inject | ||
ShadowJavaPlugin(SoftwareComponentFactory softwareComponentFactory) { | ||
this.softwareComponentFactory = softwareComponentFactory | ||
} | ||
|
||
@Override | ||
void apply(Project project) { | ||
def shadowConfiguration = project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME) | ||
def shadowTaskProvider = configureShadowTask(project, shadowConfiguration) | ||
|
||
project.configurations.named(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME) { | ||
it.extendsFrom(shadowConfiguration) | ||
} | ||
|
||
def shadowRuntimeElements = project.configurations.create(SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME) { Configuration it -> | ||
it.extendsFrom(shadowConfiguration) | ||
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)) | ||
} | ||
it.outgoing.artifact(shadowTaskProvider) | ||
} | ||
|
||
project.components.named("java", AdhocComponentWithVariants) { | ||
it.addVariantsFromConfiguration(shadowRuntimeElements) { | ||
it.mapToOptional() | ||
} | ||
} | ||
|
||
AdhocComponentWithVariants shadowComponent = softwareComponentFactory.adhoc(ShadowBasePlugin.COMPONENT_NAME) | ||
project.components.add(shadowComponent) | ||
shadowComponent.addVariantsFromConfiguration(shadowRuntimeElements) { | ||
it.mapToMavenScope("runtime") | ||
} | ||
|
||
project.plugins.withType(JavaGradlePluginPlugin).configureEach { | ||
// Remove the gradleApi so it isn't merged into the jar file. | ||
// This is required because 'java-gradle-plugin' adds gradleApi() to the 'api' configuration. | ||
// See https://github.com/gradle/gradle/blob/972c3e5c6ef990dd2190769c1ce31998a9402a79/subprojects/plugin-development/src/main/java/org/gradle/plugin/devel/plugins/JavaGradlePluginPlugin.java#L161 | ||
project.configurations.named(JavaPlugin.API_CONFIGURATION_NAME) { | ||
it.dependencies.remove(project.dependencies.gradleApi()) | ||
} | ||
// Compile only gradleApi() to make sure the plugin can compile against Gradle API. | ||
project.configurations.named(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME) { | ||
it.dependencies.add(project.dependencies.gradleApi()) | ||
} | ||
} | ||
} | ||
|
||
protected static TaskProvider<ShadowJar> configureShadowTask(Project project, Configuration shadowConfiguration) { | ||
SourceSetContainer sourceSets = project.extensions.getByType(SourceSetContainer) | ||
def jarTask = project.tasks.named(JavaPlugin.JAR_TASK_NAME, Jar) | ||
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") | ||
shadow.manifest.inheritFrom(jarTask.get().manifest) | ||
def attrProvider = jarTask.map { it.manifest.attributes.get('Class-Path') } | ||
def files = project.objects.fileCollection().from(shadowConfiguration) | ||
shadow.doFirst { | ||
if (!files.empty) { | ||
def attrs = [attrProvider.getOrElse('')] + files.collect { it.name } | ||
shadow.manifest.attributes 'Class-Path': attrs.join(' ').trim() | ||
} | ||
} | ||
shadow.from(sourceSets.main.output) | ||
shadow.configurations = [ | ||
project.configurations.findByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME) ?: | ||
project.configurations.runtime, | ||
] | ||
/* | ||
Remove excludes like this: | ||
shadowJar { | ||
... | ||
allowModuleInfos() | ||
} | ||
*/ | ||
def excludes = ['META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'] | ||
if (!shadow.isAllowModuleInfos()) { | ||
excludes.add(MODULE_INFO_CLASS) | ||
} | ||
shadow.exclude(excludes) | ||
} | ||
project.artifacts.add(shadowConfiguration.name, taskProvider) | ||
return taskProvider | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy
This file contains hidden or 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,26 @@ | ||
package com.github.jengelman.gradle.plugins.shadow.internal | ||
|
||
import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin | ||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar | ||
import java.util.jar.JarFile | ||
|
||
class RelocationUtil { | ||
|
||
static void configureRelocation(ShadowJar target, String prefix) { | ||
def packages = [] as Set<String> | ||
target.configurations.each { configuration -> | ||
configuration.files.each { jar -> | ||
JarFile jf = new JarFile(jar) | ||
jf.entries().each { entry -> | ||
if (entry.name.endsWith(".class") && entry.name != ShadowJavaPlugin.MODULE_INFO_CLASS) { | ||
packages << entry.name[0..entry.name.lastIndexOf('/') - 1].replaceAll('/', '.') | ||
} | ||
} | ||
jf.close() | ||
} | ||
} | ||
packages.each { | ||
target.relocate(it, "${prefix}.${it}") | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see so many changes are addressed in this PR, supporting including
module-info.class
is one of them, right? Can we extract this point as a separated PR?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the problem is: Including the
module-info.class
isn't directly a problem. While it's non-intuitive to include it, it's already possible.The real problem comes into play if you unknowingly add a dependency which contains also a
module-info.class
. Meaning: You have a very, really problematic file collision. Which is what this patch is about.So I added a listing, to inform about the
module-info.class
s content. But only if the user wants to include it. Because in the default settings, the module-info is excluded anyway.And after much exploration I gave up, and have to admit that johnrengelman was completely right in #710: The only clean way allow the module-info, is with an extra option.
But I already thought: Maybe I should only list the module-info's content if there is a file collision? On the other hand: That file is so important if included, I decided to list it always.