diff --git a/.editorconfig b/.editorconfig index 50d8a348..f36ddfdd 100755 --- a/.editorconfig +++ b/.editorconfig @@ -18,9 +18,5 @@ ij_kotlin_packages_to_use_import_on_demand = unset ktlint_code_style = intellij_idea ktlint_standard_function-expression-body = disabled -# TODO: this overriding will be removed in the next PR. -[*.kt] -indent_size = 4 - [*.md] trim_trailing_whitespace = false diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/DependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/DependencyFilter.kt index 46b280fb..95f54e6b 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/DependencyFilter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/DependencyFilter.kt @@ -7,48 +7,48 @@ import org.gradle.api.file.FileCollection import org.gradle.api.specs.Spec public interface DependencyFilter { - /** - * Resolve a FileCollection against the include/exclude rules in the filter - */ - public fun resolve(configuration: FileCollection): FileCollection - - /** - * Resolve all FileCollections against the include/exclude ruels in the filter and combine the results - */ - public fun resolve(configurations: Collection): FileCollection - - /** - * Exclude dependencies that match the provided spec. - */ - public fun exclude(spec: Spec): DependencyFilter - - /** - * Include dependencies that match the provided spec. - */ - public fun include(spec: Spec): DependencyFilter - - /** - * Create a spec that matches the provided project notation on group, name, and version - */ - public fun project(notation: Map): Spec - - /** - * Create a spec that matches the default configuration for the provided project path on group, name, and version - */ - public fun project(notation: String): Spec - - /** - * Create a spec that matches dependencies using the provided notation on group, name, and version - */ - public fun dependency(notation: Any): Spec - - /** - * Create a spec that matches the provided dependency on group, name, and version - */ - public fun dependency(dependency: Dependency): Spec - - /** - * Create a spec that matches the provided closure - */ - public fun dependency(spec: Closure<*>): Spec + /** + * Resolve a FileCollection against the include/exclude rules in the filter + */ + public fun resolve(configuration: FileCollection): FileCollection + + /** + * Resolve all FileCollections against the include/exclude ruels in the filter and combine the results + */ + public fun resolve(configurations: Collection): FileCollection + + /** + * Exclude dependencies that match the provided spec. + */ + public fun exclude(spec: Spec): DependencyFilter + + /** + * Include dependencies that match the provided spec. + */ + public fun include(spec: Spec): DependencyFilter + + /** + * Create a spec that matches the provided project notation on group, name, and version + */ + public fun project(notation: Map): Spec + + /** + * Create a spec that matches the default configuration for the provided project path on group, name, and version + */ + public fun project(notation: String): Spec + + /** + * Create a spec that matches dependencies using the provided notation on group, name, and version + */ + public fun dependency(notation: Any): Spec + + /** + * Create a spec that matches the provided dependency on group, name, and version + */ + public fun dependency(dependency: Dependency): Spec + + /** + * Create a spec that matches the provided closure + */ + public fun dependency(spec: Closure<*>): Spec } 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 b741d94e..de403aa9 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 @@ -19,124 +19,124 @@ import org.gradle.api.tasks.application.CreateStartScripts import org.gradle.jvm.toolchain.JavaToolchainService public class ShadowApplicationPlugin : Plugin { - private val shadowJar: TaskProvider - get() = project.tasks.named(ShadowJavaPlugin.SHADOW_JAR_TASK_NAME, ShadowJar::class.java) + private val shadowJar: TaskProvider + get() = project.tasks.named(ShadowJavaPlugin.SHADOW_JAR_TASK_NAME, ShadowJar::class.java) - private lateinit var project: Project - private lateinit var javaApplication: JavaApplication + private lateinit var project: Project + private lateinit var javaApplication: JavaApplication - override fun apply(project: Project) { - this.project = project - this.javaApplication = project.extensions.getByType(JavaApplication::class.java) + override fun apply(project: Project) { + this.project = project + this.javaApplication = project.extensions.getByType(JavaApplication::class.java) - val distributions = project.extensions.getByName("distributions") as DistributionContainer - val distribution = distributions.create("shadow") + val distributions = project.extensions.getByName("distributions") as DistributionContainer + val distribution = distributions.create("shadow") - addRunTask(project) - addCreateScriptsTask(project) - configureDistSpec(project, distribution.contents) - configureJarMainClass() - configureInstallTask(project) - } + addRunTask(project) + addCreateScriptsTask(project) + configureDistSpec(project, distribution.contents) + configureJarMainClass() + configureInstallTask(project) + } - private fun configureJarMainClass() { - val classNameProvider = javaApplication.mainClass - shadowJar.configure { jar -> - jar.inputs.property("mainClassName", classNameProvider) - jar.doFirst { - jar.manifest.attributes["Main-Class"] = classNameProvider.get() - } - } + private fun configureJarMainClass() { + val classNameProvider = javaApplication.mainClass + shadowJar.configure { jar -> + jar.inputs.property("mainClassName", classNameProvider) + jar.doFirst { + jar.manifest.attributes["Main-Class"] = classNameProvider.get() + } } + } - private fun addRunTask(project: Project) { - project.tasks.register(SHADOW_RUN_TASK_NAME, JavaJarExec::class.java) { run -> - val install = project.tasks.named(SHADOW_INSTALL_TASK_NAME, Sync::class.java) - run.dependsOn(SHADOW_INSTALL_TASK_NAME) - run.mainClass.set("-jar") - run.description = "Runs this project as a JVM application using the shadow jar" - run.group = ApplicationPlugin.APPLICATION_GROUP - run.conventionMapping.map("jvmArgs") { javaApplication.applicationDefaultJvmArgs } - run.conventionMapping.map("jarFile") { - project.file("${install.get().destinationDir.path}/lib/${shadowJar.get().archiveFile.get().asFile.name}") - } - configureJavaLauncher(run) - } + private fun addRunTask(project: Project) { + project.tasks.register(SHADOW_RUN_TASK_NAME, JavaJarExec::class.java) { run -> + val install = project.tasks.named(SHADOW_INSTALL_TASK_NAME, Sync::class.java) + run.dependsOn(SHADOW_INSTALL_TASK_NAME) + run.mainClass.set("-jar") + run.description = "Runs this project as a JVM application using the shadow jar" + run.group = ApplicationPlugin.APPLICATION_GROUP + run.conventionMapping.map("jvmArgs") { javaApplication.applicationDefaultJvmArgs } + run.conventionMapping.map("jarFile") { + project.file("${install.get().destinationDir.path}/lib/${shadowJar.get().archiveFile.get().asFile.name}") + } + configureJavaLauncher(run) } + } - private fun configureJavaLauncher(run: JavaJarExec) { - val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain - val service = project.extensions.getByType(JavaToolchainService::class.java) - val defaultLauncher = service.launcherFor(toolchain) - run.javaLauncher.set(defaultLauncher) - } + private fun configureJavaLauncher(run: JavaJarExec) { + val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain + val service = project.extensions.getByType(JavaToolchainService::class.java) + val defaultLauncher = service.launcherFor(toolchain) + run.javaLauncher.set(defaultLauncher) + } - private fun addCreateScriptsTask(project: Project) { - project.tasks.register(SHADOW_SCRIPTS_TASK_NAME, CreateStartScripts::class.java) { startScripts -> - (startScripts.unixStartScriptGenerator as DefaultTemplateBasedStartScriptGenerator).template = - project.resources.text.fromString(this::class.java.requireResourceAsText("internal/unixStartScript.txt")) - (startScripts.windowsStartScriptGenerator as DefaultTemplateBasedStartScriptGenerator).template = - project.resources.text.fromString(this::class.java.requireResourceAsText("internal/windowsStartScript.txt")) - startScripts.description = - "Creates OS specific scripts to run the project as a JVM application using the shadow jar" - startScripts.group = ApplicationPlugin.APPLICATION_GROUP - startScripts.classpath = project.files(shadowJar) - startScripts.conventionMapping.map("mainClassName") { javaApplication.mainClass.get() } - startScripts.conventionMapping.map("applicationName") { javaApplication.applicationName } - startScripts.conventionMapping.map("outputDir") { - project.layout.buildDirectory.dir("scriptsShadow").get().asFile - } - startScripts.conventionMapping.map("defaultJvmOpts") { javaApplication.applicationDefaultJvmArgs } - startScripts.inputs.files(project.objects.fileCollection().from(shadowJar)) - } + private fun addCreateScriptsTask(project: Project) { + project.tasks.register(SHADOW_SCRIPTS_TASK_NAME, CreateStartScripts::class.java) { startScripts -> + (startScripts.unixStartScriptGenerator as DefaultTemplateBasedStartScriptGenerator).template = + project.resources.text.fromString(this::class.java.requireResourceAsText("internal/unixStartScript.txt")) + (startScripts.windowsStartScriptGenerator as DefaultTemplateBasedStartScriptGenerator).template = + project.resources.text.fromString(this::class.java.requireResourceAsText("internal/windowsStartScript.txt")) + startScripts.description = + "Creates OS specific scripts to run the project as a JVM application using the shadow jar" + startScripts.group = ApplicationPlugin.APPLICATION_GROUP + startScripts.classpath = project.files(shadowJar) + startScripts.conventionMapping.map("mainClassName") { javaApplication.mainClass.get() } + startScripts.conventionMapping.map("applicationName") { javaApplication.applicationName } + startScripts.conventionMapping.map("outputDir") { + project.layout.buildDirectory.dir("scriptsShadow").get().asFile + } + startScripts.conventionMapping.map("defaultJvmOpts") { javaApplication.applicationDefaultJvmArgs } + startScripts.inputs.files(project.objects.fileCollection().from(shadowJar)) } + } - private fun configureInstallTask(project: Project) { - project.tasks.named(SHADOW_INSTALL_TASK_NAME, Sync::class.java).configure { task -> - task.doFirst { - if (task.destinationDir.isDirectory) { - if (task.destinationDir.listFiles()?.isNotEmpty() == true && - (!File(task.destinationDir, "lib").isDirectory || !File(task.destinationDir, "bin").isDirectory) - ) { - throw GradleException( - "The specified installation directory '${task.destinationDir}' is neither empty nor does it contain an installation for '${javaApplication.applicationName}'.\n" + - "If you really want to install to this directory, delete it and run the install task again.\n" + - "Alternatively, choose a different installation directory.", - ) - } - } - } - task.doLast { - task.eachFile { file -> - if (file.path == "bin/${javaApplication.applicationName}") { - file.permissions { - it.unix(0x755) - } - } - } + private fun configureInstallTask(project: Project) { + project.tasks.named(SHADOW_INSTALL_TASK_NAME, Sync::class.java).configure { task -> + task.doFirst { + if (task.destinationDir.isDirectory) { + if (task.destinationDir.listFiles()?.isNotEmpty() == true && + (!File(task.destinationDir, "lib").isDirectory || !File(task.destinationDir, "bin").isDirectory) + ) { + throw GradleException( + "The specified installation directory '${task.destinationDir}' is neither empty nor does it contain an installation for '${javaApplication.applicationName}'.\n" + + "If you really want to install to this directory, delete it and run the install task again.\n" + + "Alternatively, choose a different installation directory.", + ) + } + } + } + task.doLast { + task.eachFile { file -> + if (file.path == "bin/${javaApplication.applicationName}") { + file.permissions { + it.unix(0x755) } + } } + } } + } - private fun configureDistSpec(project: Project, distSpec: CopySpec): CopySpec { - val startScripts = project.tasks.named(SHADOW_SCRIPTS_TASK_NAME) - return distSpec.apply { - from(project.file("src/dist")) + private fun configureDistSpec(project: Project, distSpec: CopySpec): CopySpec { + val startScripts = project.tasks.named(SHADOW_SCRIPTS_TASK_NAME) + return distSpec.apply { + from(project.file("src/dist")) - into("lib") { - from(shadowJar) - from(project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME)) - } - into("bin") { - from(startScripts) - filePermissions { it.unix(493) } - } - } + into("lib") { + from(shadowJar) + from(project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME)) + } + into("bin") { + from(startScripts) + filePermissions { it.unix(493) } + } } + } - public companion object { - public const val SHADOW_RUN_TASK_NAME: String = "runShadow" - public const val SHADOW_SCRIPTS_TASK_NAME: String = "startShadowScripts" - public const val SHADOW_INSTALL_TASK_NAME: String = "installShadowDist" - } + public companion object { + public const val SHADOW_RUN_TASK_NAME: String = "runShadow" + public const val SHADOW_SCRIPTS_TASK_NAME: String = "startShadowScripts" + public const val SHADOW_INSTALL_TASK_NAME: String = "installShadowDist" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowBasePlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowBasePlugin.kt index 0c29a487..34d62be1 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowBasePlugin.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowBasePlugin.kt @@ -7,23 +7,23 @@ import org.gradle.api.Project import org.gradle.util.GradleVersion public class ShadowBasePlugin : Plugin { - override fun apply(project: Project) { - if (GradleVersion.current() < GradleVersion.version("8.3")) { - throw GradleException("This version of Shadow supports Gradle 8.3+ only. Please upgrade.") - } + override fun apply(project: Project) { + if (GradleVersion.current() < GradleVersion.version("8.3")) { + throw GradleException("This version of Shadow supports Gradle 8.3+ only. Please upgrade.") + } - project.extensions.create(EXTENSION_NAME, ShadowExtension::class.java, project) - project.configurations.create(CONFIGURATION_NAME) + project.extensions.create(EXTENSION_NAME, ShadowExtension::class.java, project) + project.configurations.create(CONFIGURATION_NAME) - project.tasks.register(KnowsTask.NAME, KnowsTask::class.java) { - it.group = ShadowJavaPlugin.SHADOW_GROUP - it.description = KnowsTask.DESC - } + project.tasks.register(KnowsTask.NAME, KnowsTask::class.java) { + it.group = ShadowJavaPlugin.SHADOW_GROUP + it.description = KnowsTask.DESC } + } - public companion object { - public const val EXTENSION_NAME: String = "shadow" - public const val CONFIGURATION_NAME: String = "shadow" - public const val COMPONENT_NAME: String = "shadow" - } + public companion object { + public const val EXTENSION_NAME: String = "shadow" + public const val CONFIGURATION_NAME: String = "shadow" + public const val COMPONENT_NAME: String = "shadow" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.kt index 255eb601..f76916b9 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.kt @@ -5,13 +5,13 @@ import org.gradle.api.publish.maven.MavenPublication @Deprecated("This is deprecated since 8.3.2") public abstract class ShadowExtension(project: Project) { - private val components = project.components + private val components = project.components - @Deprecated( - message = "configure publication using component.shadow directly.", - replaceWith = ReplaceWith("publication.from(components.getByName(\"shadow\"))"), - ) - public fun component(publication: MavenPublication) { - publication.from(components.findByName("shadow")) - } + @Deprecated( + message = "configure publication using component.shadow directly.", + replaceWith = ReplaceWith("publication.from(components.getByName(\"shadow\"))"), + ) + public fun component(publication: MavenPublication) { + publication.from(components.findByName("shadow")) + } } 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 ce5047a6..d2fd40e1 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 @@ -18,106 +18,100 @@ import org.gradle.jvm.tasks.Jar import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin public class ShadowJavaPlugin @Inject constructor( - private val softwareComponentFactory: SoftwareComponentFactory, + private val softwareComponentFactory: SoftwareComponentFactory, ) : Plugin { - override fun apply(project: Project) { - val shadowConfiguration = project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME) - val shadowTaskProvider = configureShadowTask(project, shadowConfiguration) + override fun apply(project: Project) { + val shadowConfiguration = project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME) + val shadowTaskProvider = configureShadowTask(project, shadowConfiguration) - project.configurations.named(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME) { - it.extendsFrom(shadowConfiguration) - } + project.configurations.named(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME) { + it.extendsFrom(shadowConfiguration) + } - val shadowRuntimeElements = project.configurations.create(SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME) { - it.extendsFrom(shadowConfiguration) - it.isCanBeConsumed = true - it.isCanBeResolved = false - it.attributes { attrs -> - attrs.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME)) - attrs.attribute( - Category.CATEGORY_ATTRIBUTE, - project.objects.named(Category::class.java, Category.LIBRARY), - ) - attrs.attribute( - LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, - project.objects.named(LibraryElements::class.java, LibraryElements.JAR), - ) - attrs.attribute( - Bundling.BUNDLING_ATTRIBUTE, - project.objects.named(Bundling::class.java, Bundling.SHADOWED), - ) - } - it.outgoing.artifact(shadowTaskProvider) - } + val shadowRuntimeElements = project.configurations.create(SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME) { + it.extendsFrom(shadowConfiguration) + it.isCanBeConsumed = true + it.isCanBeResolved = false + it.attributes { attrs -> + attrs.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME)) + attrs.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category::class.java, Category.LIBRARY)) + attrs.attribute( + LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, + project.objects.named(LibraryElements::class.java, LibraryElements.JAR), + ) + attrs.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling::class.java, Bundling.SHADOWED)) + } + it.outgoing.artifact(shadowTaskProvider) + } - project.components.named("java", AdhocComponentWithVariants::class.java) { - it.addVariantsFromConfiguration(shadowRuntimeElements) { variant -> - variant.mapToOptional() - } - } + project.components.named("java", AdhocComponentWithVariants::class.java) { + it.addVariantsFromConfiguration(shadowRuntimeElements) { variant -> + variant.mapToOptional() + } + } - softwareComponentFactory.adhoc(ShadowBasePlugin.COMPONENT_NAME).also { shadowComponent -> - project.components.add(shadowComponent) - shadowComponent.addVariantsFromConfiguration(shadowRuntimeElements) { variant -> - variant.mapToMavenScope("runtime") - } - } + softwareComponentFactory.adhoc(ShadowBasePlugin.COMPONENT_NAME).also { shadowComponent -> + project.components.add(shadowComponent) + shadowComponent.addVariantsFromConfiguration(shadowRuntimeElements) { variant -> + variant.mapToMavenScope("runtime") + } + } - project.plugins.withType(JavaGradlePluginPlugin::class.java).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()) - } - } + project.plugins.withType(JavaGradlePluginPlugin::class.java).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()) + } } + } - public companion object { - public const val SHADOW_JAR_TASK_NAME: String = "shadowJar" - public const val SHADOW_GROUP: String = "Shadow" - public const val SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME: String = "shadowRuntimeElements" + public companion object { + public const val SHADOW_JAR_TASK_NAME: String = "shadowJar" + public const val SHADOW_GROUP: String = "Shadow" + public const val SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME: String = "shadowRuntimeElements" - @JvmStatic - public fun configureShadowTask( - project: Project, - shadowConfiguration: Configuration, - ): TaskProvider { - val sourceSets = project.extensions.getByType(SourceSetContainer::class.java) - val jarTask = project.tasks.named(JavaPlugin.JAR_TASK_NAME, Jar::class.java) - val taskProvider = project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar::class.java) { 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) - val attrProvider = jarTask.map { it.manifest.attributes["Class-Path"] ?: "" } - val files = project.objects.fileCollection().from(shadowConfiguration) - shadow.doFirst { - if (!files.isEmpty) { - val attrs = listOf(attrProvider.get()) + files.map { it.name } - shadow.manifest.attributes["Class-Path"] = attrs.joinToString(" ").trim() - } - } - shadow.from(sourceSets.getByName("main").output) - shadow.configurations = listOfNotNull( - project.configurations.findByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME) - ?: project.configurations.getByName("runtime"), - ) - shadow.exclude( - "META-INF/INDEX.LIST", - "META-INF/*.SF", - "META-INF/*.DSA", - "META-INF/*.RSA", - "module-info.class", - ) - } - project.artifacts.add(shadowConfiguration.name, taskProvider) - return taskProvider + @JvmStatic + public fun configureShadowTask( + project: Project, + shadowConfiguration: Configuration, + ): TaskProvider { + val sourceSets = project.extensions.getByType(SourceSetContainer::class.java) + val jarTask = project.tasks.named(JavaPlugin.JAR_TASK_NAME, Jar::class.java) + val taskProvider = project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar::class.java) { 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) + val attrProvider = jarTask.map { it.manifest.attributes["Class-Path"] ?: "" } + val files = project.objects.fileCollection().from(shadowConfiguration) + shadow.doFirst { + if (!files.isEmpty) { + val attrs = listOf(attrProvider.get()) + files.map { it.name } + shadow.manifest.attributes["Class-Path"] = attrs.joinToString(" ").trim() + } } + shadow.from(sourceSets.getByName("main").output) + shadow.configurations = listOfNotNull( + project.configurations.findByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME) + ?: project.configurations.getByName("runtime"), + ) + shadow.exclude( + "META-INF/INDEX.LIST", + "META-INF/*.SF", + "META-INF/*.DSA", + "META-INF/*.RSA", + "module-info.class", + ) + } + project.artifacts.add(shadowConfiguration.name, taskProvider) + return taskProvider } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.kt index 442ca88b..f6b2c1c1 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.kt @@ -8,16 +8,16 @@ import org.gradle.api.plugins.JavaPlugin public class ShadowPlugin : Plugin { - override fun apply(project: Project) { - with(project.plugins) { - apply(ShadowBasePlugin::class.java) - apply(LegacyShadowPlugin::class.java) - withType(JavaPlugin::class.java) { - apply(ShadowJavaPlugin::class.java) - } - withType(ApplicationPlugin::class.java) { - apply(ShadowApplicationPlugin::class.java) - } - } + override fun apply(project: Project) { + with(project.plugins) { + apply(ShadowBasePlugin::class.java) + apply(LegacyShadowPlugin::class.java) + withType(JavaPlugin::class.java) { + apply(ShadowJavaPlugin::class.java) + } + withType(ApplicationPlugin::class.java) { + apply(ShadowApplicationPlugin::class.java) + } } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowStats.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowStats.kt index 55ee8f93..a3ba052e 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowStats.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowStats.kt @@ -3,53 +3,53 @@ package com.github.jengelman.gradle.plugins.shadow import org.gradle.api.GradleException public class ShadowStats { - private val relocations = mutableMapOf() - - public var totalTime: Long = 0 - public var jarStartTime: Long = 0 - public var jarEndTime: Long = 0 - public var jarCount: Int = 0 - public var processingJar: Boolean = false - - public inline val jarTiming: Long get() = jarEndTime - jarStartTime - public inline val totalTimeSecs: Double get() = totalTime / 1000.0 - public inline val averageTimePerJar: Double get() = totalTime / jarCount.toDouble() - public inline val averageTimeSecsPerJar: Double get() = averageTimePerJar / 1000 - - public fun relocate(src: String, dest: String) { - relocations[src] = dest - } - - public fun getRelocationString(): String { - return relocations.entries.joinToString("\n") { "${it.key} → ${it.value}" } - } - - public fun startJar() { - if (processingJar) throw GradleException("Can only time one entry at a time") - processingJar = true - jarStartTime = System.currentTimeMillis() - } - - public fun finishJar() { - if (processingJar) { - jarEndTime = System.currentTimeMillis() - jarCount++ - totalTime += jarTiming - processingJar = false - } - } - - public fun printStats() { - println(this) - } - - override fun toString(): String = buildString { - append("*******************\n") - append("GRADLE SHADOW STATS\n") - append("\n") - append("Total Jars: $jarCount (includes project)\n") - append("Total Time: ${totalTimeSecs}s [${totalTime}ms]\n") - append("Average Time/Jar: ${averageTimeSecsPerJar}s [${averageTimePerJar}ms]\n") - append("*******************") + private val relocations = mutableMapOf() + + public var totalTime: Long = 0 + public var jarStartTime: Long = 0 + public var jarEndTime: Long = 0 + public var jarCount: Int = 0 + public var processingJar: Boolean = false + + public inline val jarTiming: Long get() = jarEndTime - jarStartTime + public inline val totalTimeSecs: Double get() = totalTime / 1000.0 + public inline val averageTimePerJar: Double get() = totalTime / jarCount.toDouble() + public inline val averageTimeSecsPerJar: Double get() = averageTimePerJar / 1000 + + public fun relocate(src: String, dest: String) { + relocations[src] = dest + } + + public fun getRelocationString(): String { + return relocations.entries.joinToString("\n") { "${it.key} → ${it.value}" } + } + + public fun startJar() { + if (processingJar) throw GradleException("Can only time one entry at a time") + processingJar = true + jarStartTime = System.currentTimeMillis() + } + + public fun finishJar() { + if (processingJar) { + jarEndTime = System.currentTimeMillis() + jarCount++ + totalTime += jarTiming + processingJar = false } + } + + public fun printStats() { + println(this) + } + + override fun toString(): String = buildString { + append("*******************\n") + append("GRADLE SHADOW STATS\n") + append("\n") + append("Total Jars: $jarCount (includes project)\n") + append("Total Time: ${totalTimeSecs}s [${totalTime}ms]\n") + append("Average Time/Jar: ${averageTimeSecsPerJar}s [${averageTimePerJar}ms]\n") + append("*******************") + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt index 838fdae0..7be88154 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt @@ -12,74 +12,74 @@ import org.gradle.api.specs.Spec import org.gradle.api.specs.Specs internal abstract class AbstractDependencyFilter(protected val project: Project) : DependencyFilter { - private val includeSpecs = mutableListOf>() - private val excludeSpecs = mutableListOf>() + private val includeSpecs = mutableListOf>() + private val excludeSpecs = mutableListOf>() - protected abstract fun resolve( - dependencies: Set, - includedDependencies: MutableSet, - excludedDependencies: MutableSet, - ) + protected abstract fun resolve( + dependencies: Set, + includedDependencies: MutableSet, + excludedDependencies: MutableSet, + ) - override fun resolve(configuration: FileCollection): FileCollection { - val includedDeps = mutableSetOf() - val excludedDeps = mutableSetOf() - resolve( - (configuration as Configuration).resolvedConfiguration.firstLevelModuleDependencies, - includedDeps, - excludedDeps, - ) - return project.files(configuration.files) - - project.files(excludedDeps.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) }) - } + override fun resolve(configuration: FileCollection): FileCollection { + val includedDeps = mutableSetOf() + val excludedDeps = mutableSetOf() + resolve( + (configuration as Configuration).resolvedConfiguration.firstLevelModuleDependencies, + includedDeps, + excludedDeps, + ) + return project.files(configuration.files) - + project.files(excludedDeps.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) }) + } - override fun resolve(configurations: Collection): FileCollection { - return configurations.map { resolve(it) } - .reduceOrNull { acc, fileCollection -> acc + fileCollection } ?: project.files() - } + override fun resolve(configurations: Collection): FileCollection { + return configurations.map { resolve(it) } + .reduceOrNull { acc, fileCollection -> acc + fileCollection } ?: project.files() + } - override fun exclude(spec: Spec): DependencyFilter = apply { - excludeSpecs.add(spec) - } + override fun exclude(spec: Spec): DependencyFilter = apply { + excludeSpecs.add(spec) + } - override fun include(spec: Spec): DependencyFilter = apply { - includeSpecs.add(spec) - } + override fun include(spec: Spec): DependencyFilter = apply { + includeSpecs.add(spec) + } - override fun project(notation: Map): Spec { - return dependency(project.dependencies.project(notation)) - } + override fun project(notation: Map): Spec { + return dependency(project.dependencies.project(notation)) + } - override fun project(notation: String): Spec { - return dependency( - project.dependencies.project( - mapOf( - "path" to notation, - "configuration" to "default", - ), - ), - ) - } + override fun project(notation: String): Spec { + return dependency( + project.dependencies.project( + mapOf( + "path" to notation, + "configuration" to "default", + ), + ), + ) + } - override fun dependency(notation: Any): Spec { - return dependency(project.dependencies.create(notation)) - } + override fun dependency(notation: Any): Spec { + return dependency(project.dependencies.create(notation)) + } - override fun dependency(dependency: Dependency): Spec { - return dependency { it: ResolvedDependency -> - (dependency.group == null || it.moduleGroup.matches(dependency.group!!.toRegex())) && - (it.moduleName.matches(dependency.name.toRegex())) && - (dependency.version == null || it.moduleVersion.matches(dependency.version!!.toRegex())) - } + override fun dependency(dependency: Dependency): Spec { + return dependency { it: ResolvedDependency -> + (dependency.group == null || it.moduleGroup.matches(dependency.group!!.toRegex())) && + (it.moduleName.matches(dependency.name.toRegex())) && + (dependency.version == null || it.moduleVersion.matches(dependency.version!!.toRegex())) } + } - override fun dependency(spec: Closure<*>): Spec { - return Specs.convertClosureToSpec(spec) - } + override fun dependency(spec: Closure<*>): Spec { + return Specs.convertClosureToSpec(spec) + } - protected fun ResolvedDependency.isIncluded(): Boolean { - val include = includeSpecs.isEmpty() || includeSpecs.any { it.isSatisfiedBy(this) } - val exclude = excludeSpecs.isNotEmpty() && excludeSpecs.any { it.isSatisfiedBy(this) } - return include && !exclude - } + protected fun ResolvedDependency.isIncluded(): Boolean { + val include = includeSpecs.isEmpty() || includeSpecs.any { it.isSatisfiedBy(this) } + val exclude = excludeSpecs.isNotEmpty() && excludeSpecs.any { it.isSatisfiedBy(this) } + return include && !exclude + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.kt index 5b18afcf..732ce3a6 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.kt @@ -7,22 +7,22 @@ import java.util.Date import java.util.Properties internal class CleanProperties : Properties() { - @Throws(IOException::class) - override fun store(writer: Writer, comments: String) { - super.store(StripCommentsWithTimestampBufferedWriter(writer), comments) - } + @Throws(IOException::class) + override fun store(writer: Writer, comments: String) { + super.store(StripCommentsWithTimestampBufferedWriter(writer), comments) + } - private class StripCommentsWithTimestampBufferedWriter(out: Writer) : BufferedWriter(out) { - private val lengthOfExpectedTimestamp = ("#" + Date().toString()).length + private class StripCommentsWithTimestampBufferedWriter(out: Writer) : BufferedWriter(out) { + private val lengthOfExpectedTimestamp = ("#" + Date().toString()).length - @Throws(IOException::class) - override fun write(str: String) { - if (couldBeCommentWithTimestamp(str)) return - super.write(str) - } + @Throws(IOException::class) + override fun write(str: String) { + if (couldBeCommentWithTimestamp(str)) return + super.write(str) + } - private fun couldBeCommentWithTimestamp(str: String?): Boolean { - return str != null && str.startsWith("#") && str.length == lengthOfExpectedTimestamp - } + private fun couldBeCommentWithTimestamp(str: String?): Boolean { + return str != null && str.startsWith("#") && str.length == lengthOfExpectedTimestamp } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt index de5be779..da5f4e44 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt @@ -4,15 +4,15 @@ import org.gradle.api.Project import org.gradle.api.artifacts.ResolvedDependency internal class DefaultDependencyFilter(project: Project) : AbstractDependencyFilter(project) { - override fun resolve( - dependencies: Set, - includedDependencies: MutableSet, - excludedDependencies: MutableSet, - ) { - dependencies.forEach { - if (if (it.isIncluded()) includedDependencies.add(it) else excludedDependencies.add(it)) { - resolve(it.children, includedDependencies, excludedDependencies) - } - } + override fun resolve( + dependencies: Set, + includedDependencies: MutableSet, + excludedDependencies: MutableSet, + ) { + dependencies.forEach { + if (if (it.isIncluded()) includedDependencies.add(it) else excludedDependencies.add(it)) { + resolve(it.children, includedDependencies, excludedDependencies) + } } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultInheritManifest.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultInheritManifest.kt index e5b4b5ce..74bb0a53 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultInheritManifest.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultInheritManifest.kt @@ -8,29 +8,29 @@ import org.gradle.api.java.archives.internal.DefaultManifest import org.gradle.api.java.archives.internal.DefaultManifestMergeSpec internal class DefaultInheritManifest( - private val fileResolver: FileResolver, - private val internalManifest: Manifest = DefaultManifest(fileResolver), + private val fileResolver: FileResolver, + private val internalManifest: Manifest = DefaultManifest(fileResolver), ) : InheritManifest, - Manifest by internalManifest { - private val inheritMergeSpecs = mutableListOf() + Manifest by internalManifest { + private val inheritMergeSpecs = mutableListOf() - override fun inheritFrom(vararg inheritPaths: Any): InheritManifest = apply { - inheritFrom(inheritPaths, action = null) - } + override fun inheritFrom(vararg inheritPaths: Any): InheritManifest = apply { + inheritFrom(inheritPaths, action = null) + } - override fun inheritFrom(vararg inheritPaths: Any, action: Action?): InheritManifest = apply { - val mergeSpec = DefaultManifestMergeSpec() - mergeSpec.from(inheritPaths) - inheritMergeSpecs.add(mergeSpec) - action?.execute(this) - } + override fun inheritFrom(vararg inheritPaths: Any, action: Action?): InheritManifest = apply { + val mergeSpec = DefaultManifestMergeSpec() + mergeSpec.from(inheritPaths) + inheritMergeSpecs.add(mergeSpec) + action?.execute(this) + } - override fun getEffectiveManifest(): Manifest { - var base = DefaultManifest(fileResolver) - inheritMergeSpecs.forEach { - base = it.merge(base, fileResolver) - } - base.from(internalManifest) - return base.effectiveManifest + override fun getEffectiveManifest(): Manifest { + var base = DefaultManifest(fileResolver) + inheritMergeSpecs.forEach { + base = it.merge(base, fileResolver) } + base.from(internalManifest) + return base.effectiveManifest + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.kt index a2b4e6c8..a8f52c06 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.kt @@ -7,19 +7,19 @@ import org.apache.tools.zip.ZipOutputStream import org.gradle.api.UncheckedIOException internal class DefaultZipCompressor( - allowZip64Mode: Boolean, - private val entryCompressionMethod: Int, + allowZip64Mode: Boolean, + private val entryCompressionMethod: Int, ) : ZipCompressor { - private val zip64Mode: Zip64Mode = if (allowZip64Mode) Zip64Mode.AsNeeded else Zip64Mode.Never + private val zip64Mode: Zip64Mode = if (allowZip64Mode) Zip64Mode.AsNeeded else Zip64Mode.Never - override fun createArchiveOutputStream(destination: File): ZipOutputStream { - try { - return ZipOutputStream(destination).apply { - setUseZip64(zip64Mode) - setMethod(entryCompressionMethod) - } - } catch (e: Exception) { - throw UncheckedIOException("Unable to create ZIP output stream for file $destination.", e) - } + override fun createArchiveOutputStream(destination: File): ZipOutputStream { + try { + return ZipOutputStream(destination).apply { + setUseZip64(zip64Mode) + setMethod(entryCompressionMethod) + } + } catch (e: Exception) { + throw UncheckedIOException("Unable to create ZIP output stream for file $destination.", e) } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.kt index b90a7071..62b0e0bf 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.kt @@ -7,13 +7,13 @@ import org.gradle.api.tasks.TaskAction internal abstract class JavaJarExec : JavaExec() { - @get:InputFile - val jarFile: RegularFileProperty = objectFactory.fileProperty() + @get:InputFile + val jarFile: RegularFileProperty = objectFactory.fileProperty() - @TaskAction - override fun exec() { - val allArgs = listOf(jarFile.get().asFile.path) + args - setArgs(allArgs) - super.exec() - } + @TaskAction + override fun exec() { + val allArgs = listOf(jarFile.get().asFile.path) + args + setArgs(allArgs) + super.exec() + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt index b50f2aa7..2b3881cc 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt @@ -4,23 +4,23 @@ import org.gradle.api.Project import org.gradle.api.artifacts.ResolvedDependency internal class MinimizeDependencyFilter(project: Project) : AbstractDependencyFilter(project) { - override fun resolve( - dependencies: Set, - includedDependencies: MutableSet, - excludedDependencies: MutableSet, - ) { - dependencies.forEach { - val flag = it.isIncluded() && !isParentExcluded(excludedDependencies, it) - if (if (flag) includedDependencies.add(it) else excludedDependencies.add(it)) { - resolve(it.children, includedDependencies, excludedDependencies) - } - } + override fun resolve( + dependencies: Set, + includedDependencies: MutableSet, + excludedDependencies: MutableSet, + ) { + dependencies.forEach { + val flag = it.isIncluded() && !isParentExcluded(excludedDependencies, it) + if (if (flag) includedDependencies.add(it) else excludedDependencies.add(it)) { + resolve(it.children, includedDependencies, excludedDependencies) + } } + } - private fun isParentExcluded( - excludedDependencies: Set, - dependency: ResolvedDependency, - ): Boolean { - return excludedDependencies.any { dependency.parents.contains(it) } - } + private fun isParentExcluded( + excludedDependencies: Set, + dependency: ResolvedDependency, + ): Boolean { + return excludedDependencies.any { dependency.parents.contains(it) } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt index 36830703..17747b56 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt @@ -14,58 +14,58 @@ import org.objectweb.asm.commons.Remapper * @author John Engelman */ internal class RelocatorRemapper( - internal val relocators: List, - internal val stats: ShadowStats, + internal val relocators: List, + internal val stats: ShadowStats, ) : Remapper() { - private val classPattern: Pattern = Pattern.compile("(\\[*)?L(.+)") + private val classPattern: Pattern = Pattern.compile("(\\[*)?L(.+)") - fun hasRelocators(): Boolean = relocators.isNotEmpty() + fun hasRelocators(): Boolean = relocators.isNotEmpty() - override fun mapValue(value: Any): Any { - if (value is String) { - return mapStringValue(value, true) - } - return super.mapValue(value) + override fun mapValue(value: Any): Any { + if (value is String) { + return mapStringValue(value, true) } + return super.mapValue(value) + } - override fun map(internalName: String): String { - return mapStringValue(internalName, false) - } + override fun map(internalName: String): String { + return mapStringValue(internalName, false) + } - fun mapPath(path: String): String { - return map(path.substring(0, path.indexOf("."))) - } + fun mapPath(path: String): String { + return map(path.substring(0, path.indexOf("."))) + } - fun mapPath(path: ShadowCopyAction.RelativeArchivePath): String { - return mapPath(path.pathString) - } + fun mapPath(path: ShadowCopyAction.RelativeArchivePath): String { + return mapPath(path.pathString) + } - private fun mapStringValue(value: String, relocatePath: Boolean): String { - var name = value - var finalValue = name + private fun mapStringValue(value: String, relocatePath: Boolean): String { + var name = value + var finalValue = name - var prefix = "" - var suffix = "" + var prefix = "" + var suffix = "" - val m = classPattern.matcher(name) - if (m.matches()) { - prefix = m.group(1) + "L" - suffix = "" - name = m.group(2) - } + val m = classPattern.matcher(name) + if (m.matches()) { + prefix = m.group(1) + "L" + suffix = "" + name = m.group(2) + } - for (r in relocators) { - if (r.canRelocateClass(name)) { - val classContext = RelocateClassContext(name, stats) - finalValue = prefix + r.relocateClass(classContext) + suffix - break - } else if (r.canRelocatePath(name)) { - if (!relocatePath) continue - val pathContext = RelocatePathContext(name, stats) - finalValue = prefix + r.relocatePath(pathContext) + suffix - break - } - } - return finalValue + for (r in relocators) { + if (r.canRelocateClass(name)) { + val classContext = RelocateClassContext(name, stats) + finalValue = prefix + r.relocateClass(classContext) + suffix + break + } else if (r.canRelocatePath(name)) { + if (!relocatePath) continue + val pathContext = RelocatePathContext(name, stats) + finalValue = prefix + r.relocatePath(pathContext) + suffix + break + } } + return finalValue + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSpec.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSpec.kt index dbf30366..817959f1 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSpec.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSpec.kt @@ -11,61 +11,61 @@ import org.gradle.api.Action import org.gradle.api.file.CopySpec internal interface ShadowSpec : CopySpec { - fun minimize(): ShadowSpec + fun minimize(): ShadowSpec - fun minimize(action: Action?): ShadowSpec + fun minimize(action: Action?): ShadowSpec - fun dependencies(action: Action?): ShadowSpec + fun dependencies(action: Action?): ShadowSpec - @Throws( - InstantiationException::class, - IllegalAccessException::class, - NoSuchMethodException::class, - InvocationTargetException::class, - ) - fun transform(clazz: Class): ShadowSpec + @Throws( + InstantiationException::class, + IllegalAccessException::class, + NoSuchMethodException::class, + InvocationTargetException::class, + ) + fun transform(clazz: Class): ShadowSpec - @Throws( - InstantiationException::class, - IllegalAccessException::class, - NoSuchMethodException::class, - InvocationTargetException::class, - ) - fun transform(clazz: Class, action: Action?): ShadowSpec + @Throws( + InstantiationException::class, + IllegalAccessException::class, + NoSuchMethodException::class, + InvocationTargetException::class, + ) + fun transform(clazz: Class, action: Action?): ShadowSpec - fun transform(transformer: Transformer): ShadowSpec + fun transform(transformer: Transformer): ShadowSpec - fun mergeServiceFiles(): ShadowSpec + fun mergeServiceFiles(): ShadowSpec - fun mergeServiceFiles(rootPath: String): ShadowSpec + fun mergeServiceFiles(rootPath: String): ShadowSpec - fun mergeServiceFiles(action: Action?): ShadowSpec + fun mergeServiceFiles(action: Action?): ShadowSpec - fun mergeGroovyExtensionModules(): ShadowSpec + fun mergeGroovyExtensionModules(): ShadowSpec - fun append(resourcePath: String): ShadowSpec + fun append(resourcePath: String): ShadowSpec - fun relocate(pattern: String, destination: String): ShadowSpec + fun relocate(pattern: String, destination: String): ShadowSpec - fun relocate(pattern: String, destination: String, action: Action?): ShadowSpec + fun relocate(pattern: String, destination: String, action: Action?): ShadowSpec - fun relocate(relocator: Relocator): ShadowSpec + fun relocate(relocator: Relocator): ShadowSpec - @Throws( - InstantiationException::class, - IllegalAccessException::class, - NoSuchMethodException::class, - InvocationTargetException::class, - ) - fun relocate(clazz: Class): ShadowSpec + @Throws( + InstantiationException::class, + IllegalAccessException::class, + NoSuchMethodException::class, + InvocationTargetException::class, + ) + fun relocate(clazz: Class): ShadowSpec - @Throws( - InstantiationException::class, - IllegalAccessException::class, - NoSuchMethodException::class, - InvocationTargetException::class, - ) - fun relocate(clazz: Class, action: Action?): ShadowSpec + @Throws( + InstantiationException::class, + IllegalAccessException::class, + NoSuchMethodException::class, + InvocationTargetException::class, + ) + fun relocate(clazz: Class, action: Action?): ShadowSpec - val stats: ShadowStats + val stats: ShadowStats } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt index 1dd15a07..91bd6163 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt @@ -13,74 +13,74 @@ import org.vafer.jdependency.ClazzpathUnit /** Tracks unused classes in the project classpath. */ internal class UnusedTracker private constructor( - classDirs: Iterable, - classJars: FileCollection, - @InputFiles val toMinimize: FileCollection, + classDirs: Iterable, + classJars: FileCollection, + @InputFiles val toMinimize: FileCollection, ) { - private val projectUnits: List - private val cp = Clazzpath() + private val projectUnits: List + private val cp = Clazzpath() - init { - projectUnits = classDirs.map { cp.addClazzpathUnit(it) } + classJars.map { cp.addClazzpathUnit(it) } - } + init { + projectUnits = classDirs.map { cp.addClazzpathUnit(it) } + classJars.map { cp.addClazzpathUnit(it) } + } - fun findUnused(): Set { - val unused = cp.clazzes.toMutableSet() - for (cpu in projectUnits) { - unused.removeAll(cpu.clazzes) - unused.removeAll(cpu.transitiveDependencies) - } - return unused.map { it.name }.toSet() + fun findUnused(): Set { + val unused = cp.clazzes.toMutableSet() + for (cpu in projectUnits) { + unused.removeAll(cpu.clazzes) + unused.removeAll(cpu.transitiveDependencies) } + return unused.map { it.name }.toSet() + } - fun addDependency(jarOrDir: File) { - if (toMinimize.contains(jarOrDir)) { - cp.addClazzpathUnit(jarOrDir) - } + fun addDependency(jarOrDir: File) { + if (toMinimize.contains(jarOrDir)) { + cp.addClazzpathUnit(jarOrDir) } + } - companion object { - fun forProject( - apiJars: FileCollection, - sourceSetsClassesDirs: Iterable, - toMinimize: FileCollection, - ): UnusedTracker { - return UnusedTracker(sourceSetsClassesDirs, apiJars, toMinimize) - } + companion object { + fun forProject( + apiJars: FileCollection, + sourceSetsClassesDirs: Iterable, + toMinimize: FileCollection, + ): UnusedTracker { + return UnusedTracker(sourceSetsClassesDirs, apiJars, toMinimize) + } - fun getApiJarsFromProject(project: Project): FileCollection { - val apiDependencies = project.configurations.findByName("api")?.dependencies - ?: return project.files() - val runtimeConfiguration = project.configurations.findByName("runtimeClasspath") - ?: project.configurations.getByName("runtime") - val apiJars = mutableListOf() + fun getApiJarsFromProject(project: Project): FileCollection { + val apiDependencies = project.configurations.findByName("api")?.dependencies + ?: return project.files() + val runtimeConfiguration = project.configurations.findByName("runtimeClasspath") + ?: project.configurations.getByName("runtime") + val apiJars = mutableListOf() - apiDependencies.forEach { dep -> - when (dep) { - is ProjectDependency -> { - apiJars.addAll(getApiJarsFromProject(dep.dependencyProject)) - addJar(runtimeConfiguration, dep, apiJars) - } - is SelfResolvingDependency -> apiJars.addAll(dep.resolve()) - else -> { - addJar(runtimeConfiguration, dep, apiJars) - runtimeConfiguration.find { it.name.startsWith("${dep.name}-") }?.let { apiJars.add(it) } - } - } - } - return project.files(apiJars) + apiDependencies.forEach { dep -> + when (dep) { + is ProjectDependency -> { + apiJars.addAll(getApiJarsFromProject(dep.dependencyProject)) + addJar(runtimeConfiguration, dep, apiJars) + } + is SelfResolvingDependency -> apiJars.addAll(dep.resolve()) + else -> { + addJar(runtimeConfiguration, dep, apiJars) + runtimeConfiguration.find { it.name.startsWith("${dep.name}-") }?.let { apiJars.add(it) } + } } + } + return project.files(apiJars) + } - private fun isProjectDependencyFile(file: File, dep: Dependency): Boolean { - val fileName = file.name - val dependencyName = dep.name - return fileName == "$dependencyName.jar" || - (fileName.startsWith("$dependencyName-") && fileName.endsWith(".jar")) - } + private fun isProjectDependencyFile(file: File, dep: Dependency): Boolean { + val fileName = file.name + val dependencyName = dep.name + return fileName == "$dependencyName.jar" || + (fileName.startsWith("$dependencyName-") && fileName.endsWith(".jar")) + } - private fun addJar(config: Configuration, dep: Dependency, result: MutableList) { - val file = config.find { isProjectDependencyFile(it, dep) } - file?.let { result.add(it) } - } + private fun addJar(config: Configuration, dep: Dependency, result: MutableList) { + val file = config.find { isProjectDependencyFile(it, dep) } + file?.let { result.add(it) } } + } } 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 88cc763d..273ad933 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 @@ -3,20 +3,20 @@ package com.github.jengelman.gradle.plugins.shadow.internal import java.io.InputStream internal inline fun runOrThrow( - error: (e: Exception) -> Nothing = { throw RuntimeException(it) }, - block: () -> R, + error: (e: Exception) -> Nothing = { throw RuntimeException(it) }, + block: () -> R, ): R { - return try { - block() - } catch (e: Exception) { - error(e) - } + return try { + block() + } catch (e: Exception) { + error(e) + } } internal fun Class<*>.requireResourceAsText(name: String): String { - return requireResourceAsStream(name).bufferedReader().readText() + return requireResourceAsStream(name).bufferedReader().readText() } private fun Class<*>.requireResourceAsStream(name: String): InputStream { - return getResourceAsStream(name) ?: error("Resource $name not found.") + return getResourceAsStream(name) ?: error("Resource $name not found.") } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/legacy/LegacyShadowPlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/legacy/LegacyShadowPlugin.kt index 92dcf9eb..759e48eb 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/legacy/LegacyShadowPlugin.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/legacy/LegacyShadowPlugin.kt @@ -9,5 +9,5 @@ import org.gradle.api.Project * This allows older build logic to keep on working as if that old plugin ID was applied. */ public class LegacyShadowPlugin : Plugin { - override fun apply(project: Project): Unit = Unit + override fun apply(project: Project): Unit = Unit } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocateClassContext.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocateClassContext.kt index 833921d6..b5ff517f 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocateClassContext.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocateClassContext.kt @@ -3,6 +3,6 @@ package com.github.jengelman.gradle.plugins.shadow.relocation import com.github.jengelman.gradle.plugins.shadow.ShadowStats public data class RelocateClassContext( - val className: String, - val stats: ShadowStats, + val className: String, + val stats: ShadowStats, ) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatePathContext.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatePathContext.kt index dba930ad..d5df66f0 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatePathContext.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatePathContext.kt @@ -3,6 +3,6 @@ package com.github.jengelman.gradle.plugins.shadow.relocation import com.github.jengelman.gradle.plugins.shadow.ShadowStats public data class RelocatePathContext( - val path: String, - val stats: ShadowStats, + val path: String, + val stats: ShadowStats, ) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt index e0db06bd..b57e964b 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt @@ -1,3 +1,4 @@ + package com.github.jengelman.gradle.plugins.shadow.relocation /** @@ -7,18 +8,18 @@ package com.github.jengelman.gradle.plugins.shadow.relocation * @author John Engelman */ public interface Relocator { - public fun canRelocatePath(path: String): Boolean + public fun canRelocatePath(path: String): Boolean - public fun relocatePath(context: RelocatePathContext): String + public fun relocatePath(context: RelocatePathContext): String - public fun canRelocateClass(className: String): Boolean + public fun canRelocateClass(className: String): Boolean - public fun relocateClass(context: RelocateClassContext): String + public fun relocateClass(context: RelocateClassContext): String - public fun applyToSourceContent(sourceContent: String): String + public fun applyToSourceContent(sourceContent: String): String - public companion object { - @JvmField - public val ROLE: String = Relocator::class.java.name - } + public companion object { + @JvmField + public val ROLE: String = Relocator::class.java.name + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt index 5a062412..6fee7a09 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt @@ -14,137 +14,137 @@ import org.gradle.api.tasks.Optional */ @CacheableRelocator public class SimpleRelocator @JvmOverloads constructor( - patt: String?, - shadedPattern: String?, - includes: List?, - excludes: List?, - private val rawString: Boolean = false, + patt: String?, + shadedPattern: String?, + includes: List?, + excludes: List?, + private val rawString: Boolean = false, ) : Relocator { - @Input - @Optional - public val pattern: String? - - @Input - @Optional - public val pathPattern: String - - @Input - @Optional - public val shadedPattern: String? - - @Input - @Optional - public val shadedPathPattern: String - - @Input - @Optional - public val includes: MutableSet = mutableSetOf() - - @Input - @Optional - public val excludes: MutableSet = mutableSetOf() - - init { - if (rawString) { - this.pathPattern = patt.orEmpty() - this.shadedPathPattern = shadedPattern.orEmpty() - this.pattern = null - this.shadedPattern = null - } else { - this.pattern = patt?.replace('/', '.').orEmpty() - this.pathPattern = patt?.replace('.', '/').orEmpty() - this.shadedPattern = shadedPattern?.replace('/', '.') ?: "hidden.$pattern" - this.shadedPathPattern = shadedPattern?.replace('.', '/') ?: "hidden/$pathPattern" - } - this.includes += normalizePatterns(includes) - this.excludes += normalizePatterns(excludes) + @Input + @Optional + public val pattern: String? + + @Input + @Optional + public val pathPattern: String + + @Input + @Optional + public val shadedPattern: String? + + @Input + @Optional + public val shadedPathPattern: String + + @Input + @Optional + public val includes: MutableSet = mutableSetOf() + + @Input + @Optional + public val excludes: MutableSet = mutableSetOf() + + init { + if (rawString) { + this.pathPattern = patt.orEmpty() + this.shadedPathPattern = shadedPattern.orEmpty() + this.pattern = null + this.shadedPattern = null + } else { + this.pattern = patt?.replace('/', '.').orEmpty() + this.pathPattern = patt?.replace('.', '/').orEmpty() + this.shadedPattern = shadedPattern?.replace('/', '.') ?: "hidden.$pattern" + this.shadedPathPattern = shadedPattern?.replace('.', '/') ?: "hidden/$pathPattern" } + this.includes += normalizePatterns(includes) + this.excludes += normalizePatterns(excludes) + } - public fun include(pattern: String): SimpleRelocator = apply { - includes.addAll(normalizePatterns(listOf(pattern))) - } + public fun include(pattern: String): SimpleRelocator = apply { + includes.addAll(normalizePatterns(listOf(pattern))) + } - public fun exclude(pattern: String): SimpleRelocator = apply { - excludes.addAll(normalizePatterns(listOf(pattern))) - } + public fun exclude(pattern: String): SimpleRelocator = apply { + excludes.addAll(normalizePatterns(listOf(pattern))) + } - override fun canRelocatePath(path: String): Boolean { - if (rawString) { - return Pattern.compile(pathPattern).matcher(path).find() - } - if (path.length < pathPattern.length) { - return false - } - var modifiedPath = path - if (path.endsWith(".class")) { - if (path.length == 6) { - return false - } - modifiedPath = path.substring(0, path.length - 6) - } - val pathStartsWithPattern = if (modifiedPath[0] == '/') { - modifiedPath.startsWith(pathPattern, 1) - } else { - modifiedPath.startsWith(pathPattern) - } - return pathStartsWithPattern && - includes.isMatching(modifiedPath, true) && - !excludes.isMatching(modifiedPath, false) + override fun canRelocatePath(path: String): Boolean { + if (rawString) { + return Pattern.compile(pathPattern).matcher(path).find() } - - override fun canRelocateClass(className: String): Boolean { - return !rawString && className.indexOf('/') < 0 && canRelocatePath(className.replace('.', '/')) + if (path.length < pathPattern.length) { + return false } - - override fun relocatePath(context: RelocatePathContext): String { - val path = context.path - context.stats.relocate(pathPattern, shadedPathPattern) - return if (rawString) { - path.replace(pathPattern.toRegex(), shadedPathPattern) - } else { - path.replaceFirst(pathPattern, shadedPathPattern) - } + var modifiedPath = path + if (path.endsWith(".class")) { + if (path.length == 6) { + return false + } + modifiedPath = path.substring(0, path.length - 6) } - - override fun relocateClass(context: RelocateClassContext): String { - val clazz = context.className - context.stats.relocate(pathPattern, shadedPathPattern) - return clazz.replaceFirst(pattern!!.toRegex(), shadedPattern!!) + val pathStartsWithPattern = if (modifiedPath[0] == '/') { + modifiedPath.startsWith(pathPattern, 1) + } else { + modifiedPath.startsWith(pathPattern) } - - override fun applyToSourceContent(sourceContent: String): String { - return if (rawString) { - sourceContent - } else { - sourceContent.replace("\\b$pattern".toRegex(), shadedPattern!!) - } + return pathStartsWithPattern && + includes.isMatching(modifiedPath, true) && + !excludes.isMatching(modifiedPath, false) + } + + override fun canRelocateClass(className: String): Boolean { + return !rawString && className.indexOf('/') < 0 && canRelocatePath(className.replace('.', '/')) + } + + override fun relocatePath(context: RelocatePathContext): String { + val path = context.path + context.stats.relocate(pathPattern, shadedPathPattern) + return if (rawString) { + path.replace(pathPattern.toRegex(), shadedPathPattern) + } else { + path.replaceFirst(pathPattern, shadedPathPattern) } - - private fun normalizePatterns(patterns: Collection?): Set { - val normalized = mutableSetOf() - patterns?.forEach { pattern -> - if (pattern.startsWith(SelectorUtils.REGEX_HANDLER_PREFIX)) { - normalized.add(pattern) - } else { - val classPattern = pattern.replace('.', '/') - normalized.add(classPattern) - if (classPattern.endsWith("/*")) { - val packagePattern = classPattern.substring(0, classPattern.lastIndexOf('/')) - normalized.add(packagePattern) - } - } - } - return normalized + } + + override fun relocateClass(context: RelocateClassContext): String { + val clazz = context.className + context.stats.relocate(pathPattern, shadedPathPattern) + return clazz.replaceFirst(pattern!!.toRegex(), shadedPattern!!) + } + + override fun applyToSourceContent(sourceContent: String): String { + return if (rawString) { + sourceContent + } else { + sourceContent.replace("\\b$pattern".toRegex(), shadedPattern!!) } - - private fun Set.isMatching(path: String, default: Boolean): Boolean { - if (isNotEmpty()) { - forEach { pattern -> - if (SelectorUtils.matchPath(pattern, path, "/", true)) return true - } - return false + } + + private fun normalizePatterns(patterns: Collection?): Set { + val normalized = mutableSetOf() + patterns?.forEach { pattern -> + if (pattern.startsWith(SelectorUtils.REGEX_HANDLER_PREFIX)) { + normalized.add(pattern) + } else { + val classPattern = pattern.replace('.', '/') + normalized.add(classPattern) + if (classPattern.endsWith("/*")) { + val packagePattern = classPattern.substring(0, classPattern.lastIndexOf('/')) + normalized.add(packagePattern) } - return default + } + } + return normalized + } + + private fun Set.isMatching(path: String, default: Boolean): Boolean { + if (isNotEmpty()) { + forEach { pattern -> + if (SelectorUtils.matchPath(pattern, path, "/", true)) return true + } + return false } + return default + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/InheritManifest.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/InheritManifest.kt index f0987636..ca967211 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/InheritManifest.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/InheritManifest.kt @@ -4,6 +4,6 @@ import org.gradle.api.Action import org.gradle.api.java.archives.Manifest public interface InheritManifest : Manifest { - public fun inheritFrom(vararg inheritPaths: Any): InheritManifest - public fun inheritFrom(vararg inheritPaths: Any, action: Action?): InheritManifest + public fun inheritFrom(vararg inheritPaths: Any): InheritManifest + public fun inheritFrom(vararg inheritPaths: Any, action: Action?): InheritManifest } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.kt index a22c8f85..4e655630 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.kt @@ -5,14 +5,14 @@ import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction public abstract class KnowsTask : DefaultTask() { - @TaskAction - public fun knows() { - logger.info("No, The Shadow Knows....") - logger.info(this::class.java.requireResourceAsText("/shadowBanner.txt")) - } + @TaskAction + public fun knows() { + logger.info("No, The Shadow Knows....") + logger.info(this::class.java.requireResourceAsText("/shadowBanner.txt")) + } - public companion object { - public const val NAME: String = "knows" - public const val DESC: String = "Do you know who knows?" - } + public companion object { + public const val NAME: String = "knows" + public const val DESC: String = "Do you know who knows?" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt index c3aeaedc..fe63f3e3 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt @@ -43,374 +43,374 @@ import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.ClassRemapper public class ShadowCopyAction internal constructor( - private val zipFile: File, - private val compressor: ZipCompressor, - private val documentationRegistry: DocumentationRegistry, - private val encoding: String?, - private val transformers: List, - private val relocators: List, - private val patternSet: PatternSet, - private val stats: ShadowStats, - private val preserveFileTimestamps: Boolean, - private val minimizeJar: Boolean, - private val unusedTracker: UnusedTracker, + private val zipFile: File, + private val compressor: ZipCompressor, + private val documentationRegistry: DocumentationRegistry, + private val encoding: String?, + private val transformers: List, + private val relocators: List, + private val patternSet: PatternSet, + private val stats: ShadowStats, + private val preserveFileTimestamps: Boolean, + private val minimizeJar: Boolean, + private val unusedTracker: UnusedTracker, ) : CopyAction { - private val logger = LogManager.getLogger(this::class.java) - - override fun execute(stream: CopyActionProcessingStream): WorkResult { - val unusedClasses: Set = if (minimizeJar) { - stream.process( - object : BaseStreamAction() { - override fun visitFile(fileDetails: FileCopyDetails) { - if (fileDetails.isArchive) { - unusedTracker.addDependency(fileDetails.file) - } - } - }, - ) - unusedTracker.findUnused() - } else { - emptySet() - } - - val zipOutStr = try { - compressor.createArchiveOutputStream(zipFile) as ZipOutputStream - } catch (e: Exception) { - throw GradleException("Could not create ZIP '$zipFile'", e) - } - - try { - zipOutStr.use { outputStream -> - try { - val action = - StreamAction(outputStream, encoding, transformers, relocators, patternSet, unusedClasses, stats) - stream.process(action) - processTransformers(outputStream) - } catch (e: Exception) { - throw e - } + private val logger = LogManager.getLogger(this::class.java) + + override fun execute(stream: CopyActionProcessingStream): WorkResult { + val unusedClasses: Set = if (minimizeJar) { + stream.process( + object : BaseStreamAction() { + override fun visitFile(fileDetails: FileCopyDetails) { + if (fileDetails.isArchive) { + unusedTracker.addDependency(fileDetails.file) } - } catch (e: UncheckedIOException) { - if (e.cause is Zip64RequiredException) { - val message = (e.cause as Zip64RequiredException).message - throw Zip64RequiredException( - "$message\n\nTo build this archive, please enable the zip64 extension." + - "\nSee: ${documentationRegistry.getDslRefForProperty(Zip::class.java, "zip64")}", - ) - } - } - return WorkResults.didWork(true) - } - - private fun processTransformers(stream: ZipOutputStream) { - transformers.forEach { transformer -> - if (transformer.hasTransformedResource()) { - transformer.modifyOutputStream(stream, preserveFileTimestamps) - } - } + } + }, + ) + unusedTracker.findUnused() + } else { + emptySet() } - private fun getArchiveTimeFor(timestamp: Long): Long { - return if (preserveFileTimestamps) timestamp else CONSTANT_TIME_FOR_ZIP_ENTRIES + val zipOutStr = try { + compressor.createArchiveOutputStream(zipFile) as ZipOutputStream + } catch (e: Exception) { + throw GradleException("Could not create ZIP '$zipFile'", e) } - private fun setArchiveTimes(zipEntry: ZipEntry): ZipEntry { - if (!preserveFileTimestamps) { - zipEntry.time = CONSTANT_TIME_FOR_ZIP_ENTRIES + try { + zipOutStr.use { outputStream -> + try { + val action = + StreamAction(outputStream, encoding, transformers, relocators, patternSet, unusedClasses, stats) + stream.process(action) + processTransformers(outputStream) + } catch (e: Exception) { + throw e } - return zipEntry + } + } catch (e: UncheckedIOException) { + if (e.cause is Zip64RequiredException) { + val message = (e.cause as Zip64RequiredException).message + throw Zip64RequiredException( + "$message\n\nTo build this archive, please enable the zip64 extension." + + "\nSee: ${documentationRegistry.getDslRefForProperty(Zip::class.java, "zip64")}", + ) + } } + return WorkResults.didWork(true) + } + + private fun processTransformers(stream: ZipOutputStream) { + transformers.forEach { transformer -> + if (transformer.hasTransformedResource()) { + transformer.modifyOutputStream(stream, preserveFileTimestamps) + } + } + } - public abstract class BaseStreamAction : CopyActionProcessingStreamAction { - override fun processFile(details: FileCopyDetailsInternal) { - if (details.isDirectory) { - visitDir(details) - } else { - visitFile(details) - } - } + private fun getArchiveTimeFor(timestamp: Long): Long { + return if (preserveFileTimestamps) timestamp else CONSTANT_TIME_FOR_ZIP_ENTRIES + } - protected open fun visitDir(dirDetails: FileCopyDetails): Unit = Unit + private fun setArchiveTimes(zipEntry: ZipEntry): ZipEntry { + if (!preserveFileTimestamps) { + zipEntry.time = CONSTANT_TIME_FOR_ZIP_ENTRIES + } + return zipEntry + } + + public abstract class BaseStreamAction : CopyActionProcessingStreamAction { + override fun processFile(details: FileCopyDetailsInternal) { + if (details.isDirectory) { + visitDir(details) + } else { + visitFile(details) + } + } - protected abstract fun visitFile(fileDetails: FileCopyDetails) + protected open fun visitDir(dirDetails: FileCopyDetails): Unit = Unit - protected val FileCopyDetails.isArchive: Boolean get() = path.endsWith(".jar") + protected abstract fun visitFile(fileDetails: FileCopyDetails) - protected val FileCopyDetails.isClass: Boolean get() = path.endsWith(".class") - } + protected val FileCopyDetails.isArchive: Boolean get() = path.endsWith(".jar") - private inner class StreamAction( - private val zipOutStr: ZipOutputStream, - encoding: String?, - private val transformers: List, - private val relocators: List, - private val patternSet: PatternSet, - private val unused: Set, - private val stats: ShadowStats, - ) : BaseStreamAction() { - - private val remapper = RelocatorRemapper(relocators, stats) - private val visitedFiles = mutableSetOf() - - init { - if (encoding != null) { - this.zipOutStr.setEncoding(encoding) - } - } + protected val FileCopyDetails.isClass: Boolean get() = path.endsWith(".class") + } - private fun recordVisit(path: RelativePath): Boolean { - return visitedFiles.add(path.pathString) - } + private inner class StreamAction( + private val zipOutStr: ZipOutputStream, + encoding: String?, + private val transformers: List, + private val relocators: List, + private val patternSet: PatternSet, + private val unused: Set, + private val stats: ShadowStats, + ) : BaseStreamAction() { - override fun visitFile(fileDetails: FileCopyDetails) { - if (!fileDetails.isArchive) { - try { - val isClass = fileDetails.isClass - if (!remapper.hasRelocators() || !isClass) { - if (!isTransformable(fileDetails)) { - val mappedPath = remapper.map(fileDetails.relativePath.pathString) - val archiveEntry = ZipEntry(mappedPath) - archiveEntry.time = getArchiveTimeFor(fileDetails.lastModified) - archiveEntry.unixMode = UnixStat.FILE_FLAG or fileDetails.permissions.toUnixNumeric() - zipOutStr.putNextEntry(archiveEntry) - fileDetails.copyTo(zipOutStr) - zipOutStr.closeEntry() - } else { - transform(fileDetails) - } - } else if (isClass && !isUnused(fileDetails.path)) { - remapClass(fileDetails) - } - recordVisit(fileDetails.relativePath) - } catch (e: Exception) { - throw GradleException("Could not add $fileDetails to ZIP '$zipFile'.", e) - } - } else { - processArchive(fileDetails) - } - } + private val remapper = RelocatorRemapper(relocators, stats) + private val visitedFiles = mutableSetOf() - private fun processArchive(fileDetails: FileCopyDetails) { - stats.startJar() - ZipFile(fileDetails.file).use { archive -> - val archiveElements = archive.entries.toList().map { ArchiveFileTreeElement(RelativeArchivePath(it)) } - val patternSpec = patternSet.asSpec - val filteredArchiveElements = - archiveElements.filter { patternSpec.isSatisfiedBy(it.asFileTreeElement()) } - filteredArchiveElements.forEach { archiveElement -> - if (archiveElement.relativePath.isFile) { - visitArchiveFile(archiveElement, archive) - } - } - } - stats.finishJar() - } + init { + if (encoding != null) { + this.zipOutStr.setEncoding(encoding) + } + } - private fun visitArchiveDirectory(archiveDir: RelativeArchivePath) { - if (recordVisit(archiveDir)) { - zipOutStr.putNextEntry(archiveDir.entry) - zipOutStr.closeEntry() - } - } + private fun recordVisit(path: RelativePath): Boolean { + return visitedFiles.add(path.pathString) + } - private fun visitArchiveFile(archiveFile: ArchiveFileTreeElement, archive: ZipFile) { - val archiveFilePath = archiveFile.relativePath - if (archiveFile.isClassFile || !isTransformable(archiveFile)) { - if (recordVisit(archiveFilePath) && !isUnused(archiveFilePath.entry.name)) { - if (!remapper.hasRelocators() || !archiveFile.isClassFile) { - copyArchiveEntry(archiveFilePath, archive) - } else { - remapClass(archiveFilePath, archive) - } - } + override fun visitFile(fileDetails: FileCopyDetails) { + if (!fileDetails.isArchive) { + try { + val isClass = fileDetails.isClass + if (!remapper.hasRelocators() || !isClass) { + if (!isTransformable(fileDetails)) { + val mappedPath = remapper.map(fileDetails.relativePath.pathString) + val archiveEntry = ZipEntry(mappedPath) + archiveEntry.time = getArchiveTimeFor(fileDetails.lastModified) + archiveEntry.unixMode = UnixStat.FILE_FLAG or fileDetails.permissions.toUnixNumeric() + zipOutStr.putNextEntry(archiveEntry) + fileDetails.copyTo(zipOutStr) + zipOutStr.closeEntry() } else { - transform(archiveFile, archive) + transform(fileDetails) } + } else if (isClass && !isUnused(fileDetails.path)) { + remapClass(fileDetails) + } + recordVisit(fileDetails.relativePath) + } catch (e: Exception) { + throw GradleException("Could not add $fileDetails to ZIP '$zipFile'.", e) } + } else { + processArchive(fileDetails) + } + } - private fun addParentDirectories(file: RelativeArchivePath?) { - file?.let { - addParentDirectories(it.parent) - if (!it.isFile) { - visitArchiveDirectory(it) - } - } + private fun processArchive(fileDetails: FileCopyDetails) { + stats.startJar() + ZipFile(fileDetails.file).use { archive -> + val archiveElements = archive.entries.toList().map { ArchiveFileTreeElement(RelativeArchivePath(it)) } + val patternSpec = patternSet.asSpec + val filteredArchiveElements = + archiveElements.filter { patternSpec.isSatisfiedBy(it.asFileTreeElement()) } + filteredArchiveElements.forEach { archiveElement -> + if (archiveElement.relativePath.isFile) { + visitArchiveFile(archiveElement, archive) + } } + } + stats.finishJar() + } - private fun isUnused(classPath: String): Boolean { - val className = Path(classPath).nameWithoutExtension - .replace('/', '.') - val result = unused.contains(className) - if (result) { - logger.debug("Dropping unused class: $className") - } - return result - } + private fun visitArchiveDirectory(archiveDir: RelativeArchivePath) { + if (recordVisit(archiveDir)) { + zipOutStr.putNextEntry(archiveDir.entry) + zipOutStr.closeEntry() + } + } - private fun remapClass(file: RelativeArchivePath, archive: ZipFile) { - if (file.isClassFile) { - val zipEntry = setArchiveTimes(ZipEntry(remapper.mapPath(file) + ".class")) - addParentDirectories(RelativeArchivePath(zipEntry)) - remapClass(archive.getInputStream(file.entry), file.pathString, file.entry.time) - } + private fun visitArchiveFile(archiveFile: ArchiveFileTreeElement, archive: ZipFile) { + val archiveFilePath = archiveFile.relativePath + if (archiveFile.isClassFile || !isTransformable(archiveFile)) { + if (recordVisit(archiveFilePath) && !isUnused(archiveFilePath.entry.name)) { + if (!remapper.hasRelocators() || !archiveFile.isClassFile) { + copyArchiveEntry(archiveFilePath, archive) + } else { + remapClass(archiveFilePath, archive) + } } + } else { + transform(archiveFile, archive) + } + } - private fun remapClass(fileCopyDetails: FileCopyDetails) { - if (Path(fileCopyDetails.name).extension == "class") { - fileCopyDetails.file.inputStream().use { inputStream -> - remapClass( - inputStream, - fileCopyDetails.path, - fileCopyDetails.lastModified, - ) - } - } + private fun addParentDirectories(file: RelativeArchivePath?) { + file?.let { + addParentDirectories(it.parent) + if (!it.isFile) { + visitArchiveDirectory(it) } + } + } - private fun remapClass(classInputStream: InputStream, path: String, lastModified: Long) { - val cw = ClassWriter(0) - val cv = ClassRemapper(cw, remapper) + private fun isUnused(classPath: String): Boolean { + val className = Path(classPath).nameWithoutExtension + .replace('/', '.') + val result = unused.contains(className) + if (result) { + logger.debug("Dropping unused class: $className") + } + return result + } - classInputStream.use { - try { - ClassReader(it).accept(cv, ClassReader.EXPAND_FRAMES) - } catch (ise: Throwable) { - throw GradleException("Error in ASM processing class $path", ise) - } - } + private fun remapClass(file: RelativeArchivePath, archive: ZipFile) { + if (file.isClassFile) { + val zipEntry = setArchiveTimes(ZipEntry(remapper.mapPath(file) + ".class")) + addParentDirectories(RelativeArchivePath(zipEntry)) + remapClass(archive.getInputStream(file.entry), file.pathString, file.entry.time) + } + } - val renamedClass = cw.toByteArray() - val multiReleasePrefix = "^META-INF/versions/\\d+/".toRegex().find(path)?.value.orEmpty() - val mappedName = multiReleasePrefix + remapper.mapPath(path.replace(multiReleasePrefix, "")) - - renamedClass.inputStream().use { bis -> - try { - val archiveEntry = ZipEntry("$mappedName.class") - archiveEntry.time = getArchiveTimeFor(lastModified) - zipOutStr.putNextEntry(archiveEntry) - bis.copyTo(zipOutStr) - zipOutStr.closeEntry() - } catch (ignored: ZipException) { - } - } + private fun remapClass(fileCopyDetails: FileCopyDetails) { + if (Path(fileCopyDetails.name).extension == "class") { + fileCopyDetails.file.inputStream().use { inputStream -> + remapClass( + inputStream, + fileCopyDetails.path, + fileCopyDetails.lastModified, + ) } + } + } - private fun copyArchiveEntry(archiveFile: RelativeArchivePath, archive: ZipFile) { - val mappedPath = remapper.map(archiveFile.entry.name) - val entry = ZipEntry(mappedPath) - entry.time = getArchiveTimeFor(archiveFile.entry.time) - val mappedFile = RelativeArchivePath(entry) - addParentDirectories(mappedFile) - zipOutStr.putNextEntry(mappedFile.entry) - archive.getInputStream(archiveFile.entry).copyTo(zipOutStr) - zipOutStr.closeEntry() - } + private fun remapClass(classInputStream: InputStream, path: String, lastModified: Long) { + val cw = ClassWriter(0) + val cv = ClassRemapper(cw, remapper) - override fun visitDir(dirDetails: FileCopyDetails) { - try { - val path = dirDetails.relativePath.pathString + "/" - val archiveEntry = ZipEntry(path) - archiveEntry.time = getArchiveTimeFor(dirDetails.lastModified) - archiveEntry.unixMode = UnixStat.DIR_FLAG or dirDetails.permissions.toUnixNumeric() - zipOutStr.putNextEntry(archiveEntry) - zipOutStr.closeEntry() - recordVisit(dirDetails.relativePath) - } catch (e: Exception) { - throw GradleException("Could not add $dirDetails to ZIP '$zipFile'.", e) - } + classInputStream.use { + try { + ClassReader(it).accept(cv, ClassReader.EXPAND_FRAMES) + } catch (ise: Throwable) { + throw GradleException("Error in ASM processing class $path", ise) } + } - private fun transform(element: ArchiveFileTreeElement, archive: ZipFile) { - transformAndClose(element, archive.getInputStream(element.relativePath.entry)) - } + val renamedClass = cw.toByteArray() + val multiReleasePrefix = "^META-INF/versions/\\d+/".toRegex().find(path)?.value.orEmpty() + val mappedName = multiReleasePrefix + remapper.mapPath(path.replace(multiReleasePrefix, "")) - private fun transform(details: FileCopyDetails) { - transformAndClose(details, details.file.inputStream()) + renamedClass.inputStream().use { bis -> + try { + val archiveEntry = ZipEntry("$mappedName.class") + archiveEntry.time = getArchiveTimeFor(lastModified) + zipOutStr.putNextEntry(archiveEntry) + bis.copyTo(zipOutStr) + zipOutStr.closeEntry() + } catch (ignored: ZipException) { } + } + } - private fun transformAndClose(element: FileTreeElement, inputStream: InputStream) { - inputStream.use { - val mappedPath = remapper.map(element.relativePath.pathString) - transformers.find { it.canTransformResource(element) } - ?.transform( - TransformerContext.builder() - .path(mappedPath) - .inputStream(it) - .relocators(relocators) - .stats(stats) - .build(), - ) - } - } + private fun copyArchiveEntry(archiveFile: RelativeArchivePath, archive: ZipFile) { + val mappedPath = remapper.map(archiveFile.entry.name) + val entry = ZipEntry(mappedPath) + entry.time = getArchiveTimeFor(archiveFile.entry.time) + val mappedFile = RelativeArchivePath(entry) + addParentDirectories(mappedFile) + zipOutStr.putNextEntry(mappedFile.entry) + archive.getInputStream(archiveFile.entry).copyTo(zipOutStr) + zipOutStr.closeEntry() + } - private fun isTransformable(element: FileTreeElement): Boolean { - return transformers.any { it.canTransformResource(element) } - } + override fun visitDir(dirDetails: FileCopyDetails) { + try { + val path = dirDetails.relativePath.pathString + "/" + val archiveEntry = ZipEntry(path) + archiveEntry.time = getArchiveTimeFor(dirDetails.lastModified) + archiveEntry.unixMode = UnixStat.DIR_FLAG or dirDetails.permissions.toUnixNumeric() + zipOutStr.putNextEntry(archiveEntry) + zipOutStr.closeEntry() + recordVisit(dirDetails.relativePath) + } catch (e: Exception) { + throw GradleException("Could not add $dirDetails to ZIP '$zipFile'.", e) + } } - public inner class RelativeArchivePath(public val entry: ZipEntry) : - RelativePath( - !entry.isDirectory, - *entry.name.split("/").toTypedArray(), - ) { + private fun transform(element: ArchiveFileTreeElement, archive: ZipFile) { + transformAndClose(element, archive.getInputStream(element.relativePath.entry)) + } - public val isClassFile: Boolean - get() = lastName.endsWith(".class") + private fun transform(details: FileCopyDetails) { + transformAndClose(details, details.file.inputStream()) + } - override fun getParent(): RelativeArchivePath { - return if (segments.isEmpty() || segments.size == 1) { - // TODO: the return type must be non-nullable - null!! - } else { - val path = segments.dropLast(1).joinToString("/") + "/" - RelativeArchivePath(setArchiveTimes(ZipEntry(path))) - } - } + private fun transformAndClose(element: FileTreeElement, inputStream: InputStream) { + inputStream.use { + val mappedPath = remapper.map(element.relativePath.pathString) + transformers.find { it.canTransformResource(element) } + ?.transform( + TransformerContext.builder() + .path(mappedPath) + .inputStream(it) + .relocators(relocators) + .stats(stats) + .build(), + ) + } } - public class ArchiveFileTreeElement(private val archivePath: RelativeArchivePath) : FileTreeElement { + private fun isTransformable(element: FileTreeElement): Boolean { + return transformers.any { it.canTransformResource(element) } + } + } + + public inner class RelativeArchivePath(public val entry: ZipEntry) : + RelativePath( + !entry.isDirectory, + *entry.name.split("/").toTypedArray(), + ) { + + public val isClassFile: Boolean + get() = lastName.endsWith(".class") + + override fun getParent(): RelativeArchivePath { + return if (segments.isEmpty() || segments.size == 1) { + // TODO: the return type must be non-nullable + null!! + } else { + val path = segments.dropLast(1).joinToString("/") + "/" + RelativeArchivePath(setArchiveTimes(ZipEntry(path))) + } + } + } - public val isClassFile: Boolean - get() = archivePath.isClassFile + public class ArchiveFileTreeElement(private val archivePath: RelativeArchivePath) : FileTreeElement { - override fun getFile(): File = error("Not supported") + public val isClassFile: Boolean + get() = archivePath.isClassFile - override fun isDirectory(): Boolean = archivePath.entry.isDirectory + override fun getFile(): File = error("Not supported") - override fun getLastModified(): Long = archivePath.entry.lastModifiedDate.time + override fun isDirectory(): Boolean = archivePath.entry.isDirectory - override fun getSize(): Long = archivePath.entry.size + override fun getLastModified(): Long = archivePath.entry.lastModifiedDate.time - override fun open(): InputStream = error("Not supported") + override fun getSize(): Long = archivePath.entry.size - override fun copyTo(outputStream: OutputStream) {} + override fun open(): InputStream = error("Not supported") - override fun copyTo(file: File): Boolean = false + override fun copyTo(outputStream: OutputStream) {} - override fun getName(): String = archivePath.pathString + override fun copyTo(file: File): Boolean = false - override fun getPath(): String = archivePath.lastName + override fun getName(): String = archivePath.pathString - override fun getRelativePath(): RelativeArchivePath = archivePath + override fun getPath(): String = archivePath.lastName - override fun getMode(): Int = archivePath.entry.unixMode + override fun getRelativePath(): RelativeArchivePath = archivePath - override fun getPermissions(): FilePermissions = DefaultFilePermissions(mode) + override fun getMode(): Int = archivePath.entry.unixMode - public fun asFileTreeElement(): FileTreeElement { - // TODO: the param types must be non-nullable - return DefaultFileTreeElement( - null!!, - RelativePath(!isDirectory, *archivePath.segments), - null!!, - null!!, - ) - } - } + override fun getPermissions(): FilePermissions = DefaultFilePermissions(mode) - public companion object { - @JvmField - public val CONSTANT_TIME_FOR_ZIP_ENTRIES: Long = - GregorianCalendar(1980, 1, 1, 0, 0, 0).timeInMillis + public fun asFileTreeElement(): FileTreeElement { + // TODO: the param types must be non-nullable + return DefaultFileTreeElement( + null!!, + RelativePath(!isDirectory, *archivePath.segments), + null!!, + null!!, + ) } + } + + public companion object { + @JvmField + public val CONSTANT_TIME_FOR_ZIP_ENTRIES: Long = + GregorianCalendar(1980, 1, 1, 0, 0, 0).timeInMillis + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt index 87ba49a5..6e2001fc 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt @@ -47,264 +47,264 @@ import org.jetbrains.annotations.NotNull @CacheableTask public abstract class ShadowJar : - Jar(), - ShadowSpec { - private val _transformers = mutableListOf() - private val _relocators = mutableListOf() - private val _configurations = mutableListOf() - private var minimizeJar = false - private val dependencyFilterForMinimize = MinimizeDependencyFilter(project) - private var _toMinimize: FileCollection? = null - private var _apiJars: FileCollection? = null - private var _sourceSetsClassesDirs: FileCollection? = null - - init { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - manifest = DefaultInheritManifest(services.get(FileResolver::class.java)) - - inputs.property("minimize") { minimizeJar } - outputs.doNotCacheIf("Has one or more transforms or relocators that are not cacheable") { - _transformers.any { !isCacheableTransform(it::class.java) } || - _relocators.any { !isCacheableRelocator(it::class.java) } - } - } - - public var transformers: List - @Nested get() = _transformers - set(value) { - _transformers.clear() - _transformers.addAll(value) - } - - public var relocators: List - @Nested get() = _relocators - set(value) { - _relocators.clear() - _relocators.addAll(value) - } - - public var configurations: List - @Classpath get() = _configurations - set(value) { - _configurations.clear() - _configurations.addAll(value) - } - - @get:Input - public var enableRelocation: Boolean = false - - @get:Input - public var relocationPrefix: String = "shadow" - - @get:Internal - public var dependencyFilter: DependencyFilter = DefaultDependencyFilter(project) - - @get:Internal - override val stats: ShadowStats = ShadowStats() - - @get:Internal - public val internalCompressor: ZipCompressor - get() { - return when (entryCompression) { - ZipEntryCompression.DEFLATED -> DefaultZipCompressor(isZip64, ZipOutputStream.DEFLATED) - ZipEntryCompression.STORED -> DefaultZipCompressor(isZip64, ZipOutputStream.STORED) - else -> throw IllegalArgumentException("Unknown Compression type $entryCompression") - } - } - - @get:Classpath - public val toMinimize: FileCollection - get() { - if (_toMinimize == null) { - _toMinimize = if (minimizeJar) { - dependencyFilterForMinimize.resolve(_configurations).minus(apiJars) - } else { - project.objects.fileCollection() - } - } - return _toMinimize!! - } - - @get:Classpath - public val apiJars: FileCollection - get() { - if (_apiJars == null) { - _apiJars = if (minimizeJar) { - getApiJarsFromProject(project) - } else { - project.objects.fileCollection() - } - } - return _apiJars!! - } - - @get:InputFiles - @get:PathSensitive(PathSensitivity.RELATIVE) - public val sourceSetsClassesDirs: FileCollection - get() { - if (_sourceSetsClassesDirs == null) { - val allClassesDirs = project.objects.fileCollection() - if (minimizeJar) { - for (sourceSet in project.extensions.getByType(SourceSetContainer::class.java)) { - val classesDirs = sourceSet.output.classesDirs - allClassesDirs.from(classesDirs) - } - } - _sourceSetsClassesDirs = allClassesDirs.filter { file -> file.isDirectory } - } - return _sourceSetsClassesDirs!! - } - - @get:Classpath - public val includedDependencies: ConfigurableFileCollection - get() = project.files( - Callable { - dependencyFilter.resolve(_configurations) - }, - ) - - @get:Internal - public val rootPatternSet: PatternSet - get() { - return (mainSpec.buildRootResolver() as DefaultCopySpec.DefaultCopySpecResolver).patternSet - } - - override fun minimize(): ShadowJar = apply { - minimizeJar = true - } - - override fun minimize(action: Action?): ShadowJar = apply { - minimize() - action?.execute(dependencyFilterForMinimize) - } - - override fun getManifest(): InheritManifest { - return super.getManifest() as InheritManifest + Jar(), + ShadowSpec { + private val _transformers = mutableListOf() + private val _relocators = mutableListOf() + private val _configurations = mutableListOf() + private var minimizeJar = false + private val dependencyFilterForMinimize = MinimizeDependencyFilter(project) + private var _toMinimize: FileCollection? = null + private var _apiJars: FileCollection? = null + private var _sourceSetsClassesDirs: FileCollection? = null + + init { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + manifest = DefaultInheritManifest(services.get(FileResolver::class.java)) + + inputs.property("minimize") { minimizeJar } + outputs.doNotCacheIf("Has one or more transforms or relocators that are not cacheable") { + _transformers.any { !isCacheableTransform(it::class.java) } || + _relocators.any { !isCacheableRelocator(it::class.java) } } + } - @NotNull - override fun createCopyAction(): CopyAction { - val documentationRegistry = services.get(DocumentationRegistry::class.java) - val unusedTracker = if (minimizeJar) { - UnusedTracker.forProject(apiJars, _sourceSetsClassesDirs!!.files, toMinimize) - } else { - UnusedTracker.forProject(project.files(), project.files(), project.files()) - } - return ShadowCopyAction( - archiveFile.get().asFile, - internalCompressor, - documentationRegistry, - metadataCharset, - _transformers, - _relocators, - rootPatternSet, - stats, - isPreserveFileTimestamps, - minimizeJar, - unusedTracker, - ) - } - - @TaskAction - override fun copy() { - if (enableRelocation) { - configureRelocation(this, relocationPrefix) - } - from(includedDependencies) - super.copy() - logger.info(stats.toString()) - } - - override fun dependencies(action: Action?): ShadowJar = apply { - action?.execute(dependencyFilter) + public var transformers: List + @Nested get() = _transformers + set(value) { + _transformers.clear() + _transformers.addAll(value) } - override fun transform(clazz: Class): ShadowJar { - return transform(clazz, null) + public var relocators: List + @Nested get() = _relocators + set(value) { + _relocators.clear() + _relocators.addAll(value) } - override fun transform(clazz: Class, action: Action?): ShadowJar = apply { - val transformer = clazz.getDeclaredConstructor().newInstance() - addTransform(transformer, action) + public var configurations: List + @Classpath get() = _configurations + set(value) { + _configurations.clear() + _configurations.addAll(value) } - override fun transform(transformer: Transformer): ShadowJar = apply { - addTransform(transformer, null) - } + @get:Input + public var enableRelocation: Boolean = false - override fun mergeServiceFiles(): ShadowJar = runOrThrow { - transform(ServiceFileTransformer::class.java) - } + @get:Input + public var relocationPrefix: String = "shadow" - override fun mergeServiceFiles(rootPath: String): ShadowJar = runOrThrow { - transform(ServiceFileTransformer::class.java) { it.setPath(rootPath) } - } + @get:Internal + public var dependencyFilter: DependencyFilter = DefaultDependencyFilter(project) - override fun mergeServiceFiles(action: Action?): ShadowJar = runOrThrow { - transform(ServiceFileTransformer::class.java, action) - } + @get:Internal + override val stats: ShadowStats = ShadowStats() - override fun mergeGroovyExtensionModules(): ShadowJar = runOrThrow { - transform(GroovyExtensionModuleTransformer::class.java) + @get:Internal + public val internalCompressor: ZipCompressor + get() { + return when (entryCompression) { + ZipEntryCompression.DEFLATED -> DefaultZipCompressor(isZip64, ZipOutputStream.DEFLATED) + ZipEntryCompression.STORED -> DefaultZipCompressor(isZip64, ZipOutputStream.STORED) + else -> throw IllegalArgumentException("Unknown Compression type $entryCompression") + } } - override fun append(resourcePath: String): ShadowJar = runOrThrow { - transform(AppendingTransformer::class.java) { it.resource = resourcePath } - } - - override fun relocate(pattern: String, destination: String): ShadowJar { - return relocate(pattern, destination, null) - } - - override fun relocate( - pattern: String, - destination: String, - action: Action?, - ): ShadowJar = apply { - val relocator = SimpleRelocator(pattern, destination, mutableListOf(), mutableListOf()) - addRelocator(relocator, action) - } - - override fun relocate(relocator: Relocator): ShadowJar = apply { - addRelocator(relocator, null) - } - - override fun relocate(clazz: Class): ShadowJar { - return relocate(clazz, null) - } - - override fun relocate(clazz: Class, action: Action?): ShadowJar = apply { - val relocator = clazz.getDeclaredConstructor().newInstance() - addRelocator(relocator, action) + @get:Classpath + public val toMinimize: FileCollection + get() { + if (_toMinimize == null) { + _toMinimize = if (minimizeJar) { + dependencyFilterForMinimize.resolve(_configurations).minus(apiJars) + } else { + project.objects.fileCollection() + } + } + return _toMinimize!! } - private fun isCacheableTransform(clazz: Class): Boolean { - return clazz.isAnnotationPresent(CacheableTransformer::class.java) + @get:Classpath + public val apiJars: FileCollection + get() { + if (_apiJars == null) { + _apiJars = if (minimizeJar) { + getApiJarsFromProject(project) + } else { + project.objects.fileCollection() + } + } + return _apiJars!! } - private fun addTransform(transformer: T, action: Action?) { - action?.execute(transformer) - _transformers.add(transformer) + @get:InputFiles + @get:PathSensitive(PathSensitivity.RELATIVE) + public val sourceSetsClassesDirs: FileCollection + get() { + if (_sourceSetsClassesDirs == null) { + val allClassesDirs = project.objects.fileCollection() + if (minimizeJar) { + for (sourceSet in project.extensions.getByType(SourceSetContainer::class.java)) { + val classesDirs = sourceSet.output.classesDirs + allClassesDirs.from(classesDirs) + } + } + _sourceSetsClassesDirs = allClassesDirs.filter { file -> file.isDirectory } + } + return _sourceSetsClassesDirs!! } - private fun addRelocator(relocator: R, configure: Action?) { - configure?.execute(relocator) - _relocators.add(relocator) + @get:Classpath + public val includedDependencies: ConfigurableFileCollection + get() = project.files( + Callable { + dependencyFilter.resolve(_configurations) + }, + ) + + @get:Internal + public val rootPatternSet: PatternSet + get() { + return (mainSpec.buildRootResolver() as DefaultCopySpec.DefaultCopySpecResolver).patternSet } - private fun isCacheableRelocator(clazz: Class): Boolean { - return clazz.isAnnotationPresent(CacheableRelocator::class.java) + override fun minimize(): ShadowJar = apply { + minimizeJar = true + } + + override fun minimize(action: Action?): ShadowJar = apply { + minimize() + action?.execute(dependencyFilterForMinimize) + } + + override fun getManifest(): InheritManifest { + return super.getManifest() as InheritManifest + } + + @NotNull + override fun createCopyAction(): CopyAction { + val documentationRegistry = services.get(DocumentationRegistry::class.java) + val unusedTracker = if (minimizeJar) { + UnusedTracker.forProject(apiJars, _sourceSetsClassesDirs!!.files, toMinimize) + } else { + UnusedTracker.forProject(project.files(), project.files(), project.files()) } - - private fun configureRelocation(target: ShadowJar, prefix: String) { - target._configurations - .asSequence() - .flatMap { it.files } - .flatMap { JarFile(it).entries().asSequence() } - .filter { it.name.endsWith(".class") && it.name != "module-info.class" } - .forEach { - val pkg = it.name.substring(0, it.name.lastIndexOf('/')).replace('/', '.') - target.relocate(pkg, "$prefix.$pkg") - } + return ShadowCopyAction( + archiveFile.get().asFile, + internalCompressor, + documentationRegistry, + metadataCharset, + _transformers, + _relocators, + rootPatternSet, + stats, + isPreserveFileTimestamps, + minimizeJar, + unusedTracker, + ) + } + + @TaskAction + override fun copy() { + if (enableRelocation) { + configureRelocation(this, relocationPrefix) } + from(includedDependencies) + super.copy() + logger.info(stats.toString()) + } + + override fun dependencies(action: Action?): ShadowJar = apply { + action?.execute(dependencyFilter) + } + + override fun transform(clazz: Class): ShadowJar { + return transform(clazz, null) + } + + override fun transform(clazz: Class, action: Action?): ShadowJar = apply { + val transformer = clazz.getDeclaredConstructor().newInstance() + addTransform(transformer, action) + } + + override fun transform(transformer: Transformer): ShadowJar = apply { + addTransform(transformer, null) + } + + override fun mergeServiceFiles(): ShadowJar = runOrThrow { + transform(ServiceFileTransformer::class.java) + } + + override fun mergeServiceFiles(rootPath: String): ShadowJar = runOrThrow { + transform(ServiceFileTransformer::class.java) { it.setPath(rootPath) } + } + + override fun mergeServiceFiles(action: Action?): ShadowJar = runOrThrow { + transform(ServiceFileTransformer::class.java, action) + } + + override fun mergeGroovyExtensionModules(): ShadowJar = runOrThrow { + transform(GroovyExtensionModuleTransformer::class.java) + } + + override fun append(resourcePath: String): ShadowJar = runOrThrow { + transform(AppendingTransformer::class.java) { it.resource = resourcePath } + } + + override fun relocate(pattern: String, destination: String): ShadowJar { + return relocate(pattern, destination, null) + } + + override fun relocate( + pattern: String, + destination: String, + action: Action?, + ): ShadowJar = apply { + val relocator = SimpleRelocator(pattern, destination, mutableListOf(), mutableListOf()) + addRelocator(relocator, action) + } + + override fun relocate(relocator: Relocator): ShadowJar = apply { + addRelocator(relocator, null) + } + + override fun relocate(clazz: Class): ShadowJar { + return relocate(clazz, null) + } + + override fun relocate(clazz: Class, action: Action?): ShadowJar = apply { + val relocator = clazz.getDeclaredConstructor().newInstance() + addRelocator(relocator, action) + } + + private fun isCacheableTransform(clazz: Class): Boolean { + return clazz.isAnnotationPresent(CacheableTransformer::class.java) + } + + private fun addTransform(transformer: T, action: Action?) { + action?.execute(transformer) + _transformers.add(transformer) + } + + private fun addRelocator(relocator: R, configure: Action?) { + configure?.execute(relocator) + _relocators.add(relocator) + } + + private fun isCacheableRelocator(clazz: Class): Boolean { + return clazz.isAnnotationPresent(CacheableRelocator::class.java) + } + + private fun configureRelocation(target: ShadowJar, prefix: String) { + target._configurations + .asSequence() + .flatMap { it.files } + .flatMap { JarFile(it).entries().asSequence() } + .filter { it.name.endsWith(".class") && it.name != "module-info.class" } + .forEach { + val pkg = it.name.substring(0, it.name.lastIndexOf('/')).replace('/', '.') + target.relocate(pkg, "$prefix.$pkg") + } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.kt index 0db6436d..315547ef 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import org.gradle.api.file.FileTreeElement @@ -11,14 +13,14 @@ import org.gradle.api.file.FileTreeElement */ public class ApacheLicenseResourceTransformer : Transformer by NoOpTransformer { - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return LICENSE_PATH.equals(path, ignoreCase = true) || - LICENSE_TXT_PATH.regionMatches(0, path, 0, LICENSE_TXT_PATH.length, ignoreCase = true) - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return LICENSE_PATH.equals(path, ignoreCase = true) || + LICENSE_TXT_PATH.regionMatches(0, path, 0, LICENSE_TXT_PATH.length, ignoreCase = true) + } - private companion object { - const val LICENSE_PATH = "META-INF/LICENSE" - const val LICENSE_TXT_PATH = "META-INF/LICENSE.txt" - } + private companion object { + const val LICENSE_PATH = "META-INF/LICENSE" + const val LICENSE_TXT_PATH = "META-INF/LICENSE.txt" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt index 34eda8de..33b58481 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.PrintWriter @@ -18,163 +20,161 @@ import org.gradle.api.tasks.Optional */ public class ApacheNoticeResourceTransformer : Transformer { - private val entries = LinkedHashSet() - private val organizationEntries = LinkedHashMap>() + private val entries = LinkedHashSet() + private val organizationEntries = LinkedHashMap>() - @Input - public var projectName: String = "" + @Input + public var projectName: String = "" - @Input - public var addHeader: Boolean = true + @Input + public var addHeader: Boolean = true - @Input - public var preamble1: String = """ + @Input + public var preamble1: String = """ // ------------------------------------------------------------------ // NOTICE file corresponding to the section 4d of The Apache License, // Version 2.0, in this case for - """.trimIndent() - - @Input - public var preamble2: String = "\n// ------------------------------------------------------------------\n" - - @Input - public var preamble3: String = "This product includes software developed at\n" - - @Input - public var organizationName: String = "The Apache Software Foundation" - - @Input - public var organizationURL: String = "https://www.apache.org/" - - @Input - public var inceptionYear: String = "2006" - - @Optional - @Input - public var copyright: String? = null - - /** - * The file encoding of the `NOTICE` file. - */ - @Optional - @Input - public var encoding: Charset = Charsets.UTF_8 - - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return NOTICE_PATH.equals(path, ignoreCase = true) || NOTICE_TXT_PATH.equals(path, ignoreCase = true) + """.trimIndent() + + @Input + public var preamble2: String = "\n// ------------------------------------------------------------------\n" + + @Input + public var preamble3: String = "This product includes software developed at\n" + + @Input + public var organizationName: String = "The Apache Software Foundation" + + @Input + public var organizationURL: String = "https://www.apache.org/" + + @Input + public var inceptionYear: String = "2006" + + @Optional + @Input + public var copyright: String? = null + + /** + * The file encoding of the `NOTICE` file. + */ + @Optional + @Input + public var encoding: Charset = Charsets.UTF_8 + + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return NOTICE_PATH.equals(path, ignoreCase = true) || NOTICE_TXT_PATH.equals(path, ignoreCase = true) + } + + override fun transform(context: TransformerContext) { + if (entries.isEmpty()) { + val year = SimpleDateFormat("yyyy").format(Date()) + val displayYear = if (inceptionYear != year) "$inceptionYear-$year" else year + + // add headers + if (addHeader) { + entries.add("$preamble1$projectName$preamble2") + } else { + entries.add("") + } + // fake second entry, we'll look for a real one later + entries.add("$projectName\nCopyright $displayYear $organizationName\n") + entries.add("$preamble3$organizationName ($organizationURL).\n") } - override fun transform(context: TransformerContext) { - if (entries.isEmpty()) { - val year = SimpleDateFormat("yyyy").format(Date()) - val displayYear = if (inceptionYear != year) "$inceptionYear-$year" else year - - // add headers - if (addHeader) { - entries.add("$preamble1$projectName$preamble2") - } else { - entries.add("") + val reader = context.inputStream.bufferedReader(encoding) + + var line = reader.readLine() + val sb = StringBuffer() + var currentOrg: MutableSet? = null + var lineCount = 0 + while (line != null) { + val trimmedLine = line.trim() + + if (!trimmedLine.startsWith("//")) { + if (trimmedLine.isNotEmpty()) { + if (trimmedLine.startsWith("- ")) { + // resource-bundle 1.3 mode + if (lineCount == 1 && sb.toString().contains("This product includes/uses software(s) developed by")) { + currentOrg = organizationEntries.getOrPut(sb.toString().trim()) { TreeSet() } + sb.setLength(0) + } else if (sb.isNotEmpty() && currentOrg != null) { + currentOrg.add(sb.toString()) + sb.setLength(0) } - // fake second entry, we'll look for a real one later - entries.add("$projectName\nCopyright $displayYear $organizationName\n") - entries.add("$preamble3$organizationName ($organizationURL).\n") + } + sb.append(line).append("\n") + lineCount++ + } else { + val ent = sb.toString() + if (ent.startsWith(projectName) && ent.contains("Copyright ")) { + copyright = ent + } + if (currentOrg == null) { + entries.add(ent) + } else { + currentOrg.add(ent) + } + sb.setLength(0) + lineCount = 0 + currentOrg = null } + } - val reader = context.inputStream.bufferedReader(encoding) - - var line = reader.readLine() - val sb = StringBuffer() - var currentOrg: MutableSet? = null - var lineCount = 0 - while (line != null) { - val trimmedLine = line.trim() - - if (!trimmedLine.startsWith("//")) { - if (trimmedLine.isNotEmpty()) { - if (trimmedLine.startsWith("- ")) { - // resource-bundle 1.3 mode - if (lineCount == 1 && sb.toString() - .contains("This product includes/uses software(s) developed by") - ) { - currentOrg = organizationEntries.getOrPut(sb.toString().trim()) { TreeSet() } - sb.setLength(0) - } else if (sb.isNotEmpty() && currentOrg != null) { - currentOrg.add(sb.toString()) - sb.setLength(0) - } - } - sb.append(line).append("\n") - lineCount++ - } else { - val ent = sb.toString() - if (ent.startsWith(projectName) && ent.contains("Copyright ")) { - copyright = ent - } - if (currentOrg == null) { - entries.add(ent) - } else { - currentOrg.add(ent) - } - sb.setLength(0) - lineCount = 0 - currentOrg = null - } - } - - line = reader.readLine() - } - if (sb.isNotEmpty()) { - if (currentOrg == null) { - entries.add(sb.toString()) - } else { - currentOrg.add(sb.toString()) - } - } + line = reader.readLine() } - - override fun hasTransformedResource(): Boolean = true - - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val zipEntry = ZipEntry(NOTICE_PATH) - zipEntry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, zipEntry.time) - os.putNextEntry(zipEntry) - - val writer = PrintWriter(os.writer(encoding)) - - var count = 0 - for (line in entries) { - ++count - if (line == copyright && count != 2) { - continue - } - - if (count == 2 && copyright != null) { - writer.print(copyright) - writer.print('\n') - } else { - writer.print(line) - writer.print('\n') - } - if (count == 3) { - // do org stuff - for ((key, value) in organizationEntries) { - writer.print(key) - writer.print('\n') - for (l in value) { - writer.print(l) - } - writer.print('\n') - } - } + if (sb.isNotEmpty()) { + if (currentOrg == null) { + entries.add(sb.toString()) + } else { + currentOrg.add(sb.toString()) + } + } + } + + override fun hasTransformedResource(): Boolean = true + + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val zipEntry = ZipEntry(NOTICE_PATH) + zipEntry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, zipEntry.time) + os.putNextEntry(zipEntry) + + val writer = PrintWriter(os.writer(encoding)) + + var count = 0 + for (line in entries) { + ++count + if (line == copyright && count != 2) { + continue + } + + if (count == 2 && copyright != null) { + writer.print(copyright) + writer.print('\n') + } else { + writer.print(line) + writer.print('\n') + } + if (count == 3) { + // do org stuff + for ((key, value) in organizationEntries) { + writer.print(key) + writer.print('\n') + for (l in value) { + writer.print(l) + } + writer.print('\n') } - - writer.flush() - entries.clear() + } } - private companion object { - const val NOTICE_PATH = "META-INF/NOTICE" - const val NOTICE_TXT_PATH = "META-INF/NOTICE.txt" - } + writer.flush() + entries.clear() + } + + private companion object { + const val NOTICE_PATH = "META-INF/NOTICE" + const val NOTICE_TXT_PATH = "META-INF/NOTICE.txt" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformer.kt index 7fe767a0..a4d7d324 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.ByteArrayOutputStream @@ -17,45 +19,45 @@ import org.gradle.api.tasks.Optional @CacheableTransformer public class AppendingTransformer : Transformer { - @Optional - @Input - public var resource: String? = null + @Optional + @Input + public var resource: String? = null + + /** + * Defer initialization, see https://github.com/GradleUp/shadow/issues/763 + */ + private var data: ByteArrayOutputStream? = null - /** - * Defer initialization, see https://github.com/GradleUp/shadow/issues/763 - */ - private var data: ByteArrayOutputStream? = null + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return resource?.equals(path, ignoreCase = true) ?: false + } - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return resource?.equals(path, ignoreCase = true) ?: false + override fun transform(context: TransformerContext) { + if (data == null) { + data = ByteArrayOutputStream() } - override fun transform(context: TransformerContext) { - if (data == null) { - data = ByteArrayOutputStream() - } + context.inputStream.copyTo(data!!) + data!!.write('\n'.code) - context.inputStream.copyTo(data!!) - data!!.write('\n'.code) + context.inputStream.close() + } - context.inputStream.close() - } + override fun hasTransformedResource(): Boolean { + return (data?.size() ?: 0) > 0 + } - override fun hasTransformedResource(): Boolean { - return (data?.size() ?: 0) > 0 + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + if (data == null) { + data = ByteArrayOutputStream() } - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - if (data == null) { - data = ByteArrayOutputStream() - } - - val entry = ZipEntry(resource) - entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) - os.putNextEntry(entry) + val entry = ZipEntry(resource) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) - data!!.toByteArray().inputStream().copyTo(os) - data!!.reset() - } + data!!.toByteArray().inputStream().copyTo(os) + data!!.reset() + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.kt index c503d44b..330f3df7 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext @@ -21,123 +23,123 @@ import org.gradle.api.file.FileTreeElement * @author John Engelman */ public class ComponentsXmlResourceTransformer : Transformer { - private val components: MutableMap = LinkedHashMap() - - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return COMPONENTS_XML_PATH == path - } - - override fun transform(context: TransformerContext) { - val newDom: Xpp3Dom = try { - val bis = object : BufferedInputStream(context.inputStream) { - @Throws(IOException::class) - override fun close() { - // leave ZIP open - } - } - Xpp3DomBuilder.build(XmlStreamReader(bis)) - } catch (e: Exception) { - throw IOException("Error parsing components.xml in ${context.inputStream}", e) + private val components: MutableMap = LinkedHashMap() + + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return COMPONENTS_XML_PATH == path + } + + override fun transform(context: TransformerContext) { + val newDom: Xpp3Dom = try { + val bis = object : BufferedInputStream(context.inputStream) { + @Throws(IOException::class) + override fun close() { + // leave ZIP open } + } + Xpp3DomBuilder.build(XmlStreamReader(bis)) + } catch (e: Exception) { + throw IOException("Error parsing components.xml in ${context.inputStream}", e) + } - // Only try to merge in components if there are some elements in the component-set - if (newDom.getChild("components") == null) return - - val children = newDom.getChild("components").getChildren("component") - - for (component in children) { - var role = getValue(component, "role") - role = getRelocatedClass(role, context) - setValue(component, "role", role) - - val roleHint = getValue(component, "role-hint") + // Only try to merge in components if there are some elements in the component-set + if (newDom.getChild("components") == null) return - var impl = getValue(component, "implementation") - impl = getRelocatedClass(impl, context) - setValue(component, "implementation", impl) + val children = newDom.getChild("components").getChildren("component") - val key = "$role:$roleHint" - if (components.containsKey(key)) { - // TODO: use the tools in Plexus to merge these properly. For now, I just need an all-or-nothing - // configuration carry over + for (component in children) { + var role = getValue(component, "role") + role = getRelocatedClass(role, context) + setValue(component, "role", role) - val dom = components[key] - if (dom?.getChild("configuration") != null) { - component.addChild(dom.getChild("configuration")) - } - } + val roleHint = getValue(component, "role-hint") - val requirements = component.getChild("requirements") - if (requirements != null && requirements.childCount > 0) { - for (r in requirements.childCount - 1 downTo 0) { - val requirement = requirements.getChild(r) + var impl = getValue(component, "implementation") + impl = getRelocatedClass(impl, context) + setValue(component, "implementation", impl) - var requiredRole = getValue(requirement, "role") - requiredRole = getRelocatedClass(requiredRole, context) - setValue(requirement, "role", requiredRole) - } - } + val key = "$role:$roleHint" + if (components.containsKey(key)) { + // TODO: use the tools in Plexus to merge these properly. For now, I just need an all-or-nothing + // configuration carry over - components[key] = component + val dom = components[key] + if (dom?.getChild("configuration") != null) { + component.addChild(dom.getChild("configuration")) } - } + } - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val data = getTransformedResource() - val entry = ZipEntry(COMPONENTS_XML_PATH) - entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) - os.putNextEntry(entry) - data.inputStream().copyTo(os) - components.clear() - } - - override fun hasTransformedResource(): Boolean = components.isNotEmpty() - - @Throws(IOException::class) - private fun getTransformedResource(): ByteArray { - val baos = ByteArrayOutputStream(1024 * 4) - XmlStreamWriter(baos).use { writer -> - val dom = Xpp3Dom("component-set") - val componentDom = Xpp3Dom("components") - dom.addChild(componentDom) + val requirements = component.getChild("requirements") + if (requirements != null && requirements.childCount > 0) { + for (r in requirements.childCount - 1 downTo 0) { + val requirement = requirements.getChild(r) - for (component in components.values) { - componentDom.addChild(component) - } - - Xpp3DomWriter.write(writer, dom) + var requiredRole = getValue(requirement, "role") + requiredRole = getRelocatedClass(requiredRole, context) + setValue(requirement, "role", requiredRole) } - return baos.toByteArray() - } + } - private fun getRelocatedClass(className: String?, context: TransformerContext): String { - val relocators = context.relocators - val stats = context.stats - if (!className.isNullOrEmpty()) { - for (relocator in relocators) { - if (relocator.canRelocateClass(className)) { - val relocateClassContext = RelocateClassContext(className, stats) - return relocator.relocateClass(relocateClassContext) - } - } - } - return className.orEmpty() + components[key] = component } - - private fun getValue(dom: Xpp3Dom, element: String): String { - val child = dom.getChild(element) - return child?.value.orEmpty() + } + + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val data = getTransformedResource() + val entry = ZipEntry(COMPONENTS_XML_PATH) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) + data.inputStream().copyTo(os) + components.clear() + } + + override fun hasTransformedResource(): Boolean = components.isNotEmpty() + + @Throws(IOException::class) + private fun getTransformedResource(): ByteArray { + val baos = ByteArrayOutputStream(1024 * 4) + XmlStreamWriter(baos).use { writer -> + val dom = Xpp3Dom("component-set") + val componentDom = Xpp3Dom("components") + dom.addChild(componentDom) + + for (component in components.values) { + componentDom.addChild(component) + } + + Xpp3DomWriter.write(writer, dom) } - - private fun setValue(dom: Xpp3Dom, element: String, value: String) { - val child = dom.getChild(element) - if (child != null && value.isNotEmpty()) { - child.value = value + return baos.toByteArray() + } + + private fun getRelocatedClass(className: String?, context: TransformerContext): String { + val relocators = context.relocators + val stats = context.stats + if (!className.isNullOrEmpty()) { + for (relocator in relocators) { + if (relocator.canRelocateClass(className)) { + val relocateClassContext = RelocateClassContext(className, stats) + return relocator.relocateClass(relocateClassContext) } + } } - - public companion object { - public const val COMPONENTS_XML_PATH: String = "META-INF/plexus/components.xml" + return className.orEmpty() + } + + private fun getValue(dom: Xpp3Dom, element: String): String { + val child = dom.getChild(element) + return child?.value.orEmpty() + } + + private fun setValue(dom: Xpp3Dom, element: String, value: String) { + val child = dom.getChild(element) + if (child != null && value.isNotEmpty()) { + child.value = value } + } + + public companion object { + public const val COMPONENTS_XML_PATH: String = "META-INF/plexus/components.xml" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DontIncludeResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DontIncludeResourceTransformer.kt index f13cbadf..85dc6b94 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DontIncludeResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DontIncludeResourceTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import org.gradle.api.file.FileTreeElement @@ -14,12 +16,12 @@ import org.gradle.api.tasks.Optional */ public class DontIncludeResourceTransformer : Transformer by NoOpTransformer { - @Optional - @Input - public var resource: String? = null + @Optional + @Input + public var resource: String? = null - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return !resource.isNullOrEmpty() && path.endsWith(resource!!) - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return !resource.isNullOrEmpty() && path.endsWith(resource!!) + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.kt index 75952a1d..02f80fe1 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.kt @@ -1,3 +1,4 @@ + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.ByteArrayOutputStream @@ -10,83 +11,82 @@ import org.gradle.api.file.FileTreeElement @CacheableTransformer public class GroovyExtensionModuleTransformer : Transformer { - private val module = Properties() + private val module = Properties() - /** - * default to Groovy 2.4 or earlier - */ - private var legacy = true + /** + * default to Groovy 2.4 or earlier + */ + private var legacy = true - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return when (path) { - GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH -> { - // Groovy 2.5+ - legacy = false - true - } - GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH -> true - else -> false - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return when (path) { + GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH -> { + // Groovy 2.5+ + legacy = false + true + } + GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH -> true + else -> false } + } - override fun transform(context: TransformerContext) { - val props = Properties() - props.load(context.inputStream) - props.forEach { key, value -> - when (key as String) { - MODULE_NAME_KEY -> handle(key, value as String) { - module.setProperty(key, MERGED_MODULE_NAME) - } - MODULE_VERSION_KEY -> handle(key, value as String) { - module.setProperty(key, MERGED_MODULE_VERSION) - } - EXTENSION_CLASSES_KEY, STATIC_EXTENSION_CLASSES_KEY -> handle(key, value as String) { existingValue -> - val newValue = "$existingValue,$value" - module.setProperty(key, newValue) - } - } + override fun transform(context: TransformerContext) { + val props = Properties() + props.load(context.inputStream) + props.forEach { key, value -> + when (key as String) { + MODULE_NAME_KEY -> handle(key, value as String) { + module.setProperty(key, MERGED_MODULE_NAME) + } + MODULE_VERSION_KEY -> handle(key, value as String) { + module.setProperty(key, MERGED_MODULE_VERSION) + } + EXTENSION_CLASSES_KEY, STATIC_EXTENSION_CLASSES_KEY -> handle(key, value as String) { existingValue -> + val newValue = "$existingValue,$value" + module.setProperty(key, newValue) } + } } + } - private fun handle(key: String, value: String, mergeValue: (String) -> Unit) { - val existingValue = module.getProperty(key) - if (existingValue != null) { - mergeValue(existingValue) - } else { - module.setProperty(key, value) - } + private fun handle(key: String, value: String, mergeValue: (String) -> Unit) { + val existingValue = module.getProperty(key) + if (existingValue != null) { + mergeValue(existingValue) + } else { + module.setProperty(key, value) } + } - override fun hasTransformedResource(): Boolean = module.isNotEmpty() + override fun hasTransformedResource(): Boolean = module.isNotEmpty() - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val path = - if (legacy) GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH else GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH - val entry = ZipEntry(path).apply { - time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) - } - os.putNextEntry(entry) - module.toInputStream().copyTo(os) - os.closeEntry() + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val path = if (legacy) GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH else GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH + val entry = ZipEntry(path).apply { + time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) } + os.putNextEntry(entry) + module.toInputStream().copyTo(os) + os.closeEntry() + } - private fun Properties.toInputStream(): InputStream { - val baos = ByteArrayOutputStream() - this.store(baos, null) - return baos.toByteArray().inputStream() - } + private fun Properties.toInputStream(): InputStream { + val baos = ByteArrayOutputStream() + this.store(baos, null) + return baos.toByteArray().inputStream() + } - private companion object { - const val GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH = - "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" - const val GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH = - "META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule" - const val MODULE_NAME_KEY = "moduleName" - const val MODULE_VERSION_KEY = "moduleVersion" - const val EXTENSION_CLASSES_KEY = "extensionClasses" - const val STATIC_EXTENSION_CLASSES_KEY = "staticExtensionClasses" - const val MERGED_MODULE_NAME = "MergedByShadowJar" - const val MERGED_MODULE_VERSION = "1.0.0" - } + private companion object { + const val GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH = + "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" + const val GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH = + "META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule" + const val MODULE_NAME_KEY = "moduleName" + const val MODULE_VERSION_KEY = "moduleVersion" + const val EXTENSION_CLASSES_KEY = "extensionClasses" + const val STATIC_EXTENSION_CLASSES_KEY = "staticExtensionClasses" + const val MERGED_MODULE_NAME = "MergedByShadowJar" + const val MERGED_MODULE_VERSION = "1.0.0" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/IncludeResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/IncludeResourceTransformer.kt index b87db65e..925300a3 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/IncludeResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/IncludeResourceTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.File @@ -18,22 +20,22 @@ import org.gradle.api.tasks.PathSensitivity */ public class IncludeResourceTransformer : Transformer by NoOpTransformer { - @InputFile - @PathSensitive(PathSensitivity.NONE) - public lateinit var file: File + @InputFile + @PathSensitive(PathSensitivity.NONE) + public lateinit var file: File - @Input - public lateinit var resource: String + @Input + public lateinit var resource: String - override fun hasTransformedResource(): Boolean { - return this::file.isInitialized && file.exists() - } + override fun hasTransformedResource(): Boolean { + return this::file.isInitialized && file.exists() + } - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val entry = ZipEntry(resource) - entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) - os.putNextEntry(entry) + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val entry = ZipEntry(resource) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) - file.inputStream().copyTo(os) - } + file.inputStream().copyTo(os) + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt index a57d58fe..76a839c9 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.ShadowStats @@ -17,69 +19,69 @@ import org.gradle.api.file.FileTreeElement @CacheableTransformer public class Log4j2PluginsCacheFileTransformer : Transformer { - private val temporaryFiles = mutableListOf() - private val relocators = mutableListOf() - private var stats: ShadowStats? = null + private val temporaryFiles = mutableListOf() + private val relocators = mutableListOf() + private var stats: ShadowStats? = null - override fun canTransformResource(element: FileTreeElement): Boolean { - return PLUGIN_CACHE_FILE == element.name - } + override fun canTransformResource(element: FileTreeElement): Boolean { + return PLUGIN_CACHE_FILE == element.name + } - override fun transform(context: TransformerContext) { - val inputStream = context.inputStream - val temporaryFile = File.createTempFile("Log4j2Plugins", ".dat") - temporaryFile.deleteOnExit() - temporaryFiles.add(temporaryFile) - FileOutputStream(temporaryFile).use { fos -> - inputStream.copyTo(fos) - } - relocators.addAll(context.relocators) - if (stats == null) { - stats = context.stats - } + override fun transform(context: TransformerContext) { + val inputStream = context.inputStream + val temporaryFile = File.createTempFile("Log4j2Plugins", ".dat") + temporaryFile.deleteOnExit() + temporaryFiles.add(temporaryFile) + FileOutputStream(temporaryFile).use { fos -> + inputStream.copyTo(fos) } - - override fun hasTransformedResource(): Boolean { - val hasTransformedMultipleFiles = temporaryFiles.size > 1 - val hasAtLeastOneFileAndRelocator = temporaryFiles.isNotEmpty() && relocators.isNotEmpty() - return hasTransformedMultipleFiles || hasAtLeastOneFileAndRelocator + relocators.addAll(context.relocators) + if (stats == null) { + stats = context.stats } + } - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val pluginCache = PluginCache() - pluginCache.loadCacheFiles(urlEnumeration) - relocatePlugins(pluginCache) - val entry = ZipEntry(PLUGIN_CACHE_FILE).apply { - time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) - } - os.putNextEntry(entry) - pluginCache.writeCache(CloseShieldOutputStream.wrap(os)) - temporaryFiles.clear() + override fun hasTransformedResource(): Boolean { + val hasTransformedMultipleFiles = temporaryFiles.size > 1 + val hasAtLeastOneFileAndRelocator = temporaryFiles.isNotEmpty() && relocators.isNotEmpty() + return hasTransformedMultipleFiles || hasAtLeastOneFileAndRelocator + } + + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val pluginCache = PluginCache() + pluginCache.loadCacheFiles(urlEnumeration) + relocatePlugins(pluginCache) + val entry = ZipEntry(PLUGIN_CACHE_FILE).apply { + time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) } + os.putNextEntry(entry) + pluginCache.writeCache(CloseShieldOutputStream.wrap(os)) + temporaryFiles.clear() + } - private val urlEnumeration: Enumeration - get() { - val urls = temporaryFiles.map { it.toURI().toURL() } - return Collections.enumeration(urls) - } + private val urlEnumeration: Enumeration + get() { + val urls = temporaryFiles.map { it.toURI().toURL() } + return Collections.enumeration(urls) + } - private fun relocatePlugins(pluginCache: PluginCache) { - for (currentMap in pluginCache.allCategories.values) { - for (currentPluginEntry in currentMap.values) { - val className = currentPluginEntry.className - val relocateClassContext = RelocateClassContext(className, stats!!) - for (currentRelocator in relocators) { - if (currentRelocator.canRelocateClass(className)) { - val relocatedClassName = currentRelocator.relocateClass(relocateClassContext) - currentPluginEntry.className = relocatedClassName - break - } - } - } + private fun relocatePlugins(pluginCache: PluginCache) { + for (currentMap in pluginCache.allCategories.values) { + for (currentPluginEntry in currentMap.values) { + val className = currentPluginEntry.className + val relocateClassContext = RelocateClassContext(className, stats!!) + for (currentRelocator in relocators) { + if (currentRelocator.canRelocateClass(className)) { + val relocatedClassName = currentRelocator.relocateClass(relocateClassContext) + currentPluginEntry.className = relocatedClassName + break + } } + } } + } - private companion object { - const val PLUGIN_CACHE_FILE = "org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat" - } + private companion object { + const val PLUGIN_CACHE_FILE = "org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformer.kt index f4dab55b..6785d98e 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.IOException @@ -11,50 +13,50 @@ import org.slf4j.LoggerFactory @CacheableTransformer public class ManifestAppenderTransformer : Transformer { - private val logger = LoggerFactory.getLogger(this::class.java) + private val logger = LoggerFactory.getLogger(this::class.java) - private val _attributes = mutableListOf>>() - private var manifestContents = ByteArray(0) + private val _attributes = mutableListOf>>() + private var manifestContents = ByteArray(0) - @Input - public val attributes: List>> = _attributes + @Input + public val attributes: List>> = _attributes - public fun append(name: String, value: Comparable<*>): ManifestAppenderTransformer = apply { - _attributes.add(name to value) - } + public fun append(name: String, value: Comparable<*>): ManifestAppenderTransformer = apply { + _attributes.add(name to value) + } - override fun canTransformResource(element: FileTreeElement): Boolean { - return MANIFEST_NAME.equals(element.relativePath.pathString, ignoreCase = true) - } + override fun canTransformResource(element: FileTreeElement): Boolean { + return MANIFEST_NAME.equals(element.relativePath.pathString, ignoreCase = true) + } - override fun transform(context: TransformerContext) { - if (manifestContents.isEmpty()) { - try { - manifestContents = context.inputStream.readBytes() - } catch (e: IOException) { - logger.warn("Failed to read MANIFEST.MF", e) - } - } + override fun transform(context: TransformerContext) { + if (manifestContents.isEmpty()) { + try { + manifestContents = context.inputStream.readBytes() + } catch (e: IOException) { + logger.warn("Failed to read MANIFEST.MF", e) + } } + } + + override fun hasTransformedResource(): Boolean = attributes.isNotEmpty() - override fun hasTransformedResource(): Boolean = attributes.isNotEmpty() - - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val entry = ZipEntry(MANIFEST_NAME).apply { - time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) - } - os.putNextEntry(entry) - os.write(manifestContents) - - if (_attributes.isNotEmpty()) { - _attributes.forEach { (name, value) -> - os.write(name.toByteArray(UTF_8)) - os.write(": ".toByteArray(UTF_8)) - os.write(value.toString().toByteArray(UTF_8)) - os.write("\r\n".toByteArray(UTF_8)) - } - os.write("\r\n".toByteArray(UTF_8)) - _attributes.clear() - } + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val entry = ZipEntry(MANIFEST_NAME).apply { + time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) + } + os.putNextEntry(entry) + os.write(manifestContents) + + if (_attributes.isNotEmpty()) { + _attributes.forEach { (name, value) -> + os.write(name.toByteArray(UTF_8)) + os.write(": ".toByteArray(UTF_8)) + os.write(value.toString().toByteArray(UTF_8)) + os.write("\r\n".toByteArray(UTF_8)) + } + os.write("\r\n".toByteArray(UTF_8)) + _attributes.clear() } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestResourceTransformer.kt index a056c496..805decf3 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestResourceTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.IOException @@ -13,63 +15,63 @@ import org.gradle.api.tasks.Optional @CacheableTransformer public class ManifestResourceTransformer : Transformer { - private val logger = LogManager.getLogger(this::class.java) + private val logger = LogManager.getLogger(this::class.java) - @Optional - @Input - public var mainClass: String? = null + @Optional + @Input + public var mainClass: String? = null - @Optional - @Input - public var manifestEntries: MutableMap? = null + @Optional + @Input + public var manifestEntries: MutableMap? = null - private var manifestDiscovered = false - private var manifest: Manifest? = null + private var manifestDiscovered = false + private var manifest: Manifest? = null - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return JarFile.MANIFEST_NAME.equals(path, ignoreCase = true) - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return JarFile.MANIFEST_NAME.equals(path, ignoreCase = true) + } - override fun transform(context: TransformerContext) { - if (!manifestDiscovered) { - try { - manifest = Manifest(context.inputStream) - manifestDiscovered = true - } catch (e: IOException) { - logger.warn("Failed to read MANIFEST.MF", e) - } - } + override fun transform(context: TransformerContext) { + if (!manifestDiscovered) { + try { + manifest = Manifest(context.inputStream) + manifestDiscovered = true + } catch (e: IOException) { + logger.warn("Failed to read MANIFEST.MF", e) + } } + } - override fun hasTransformedResource(): Boolean = true + override fun hasTransformedResource(): Boolean = true - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - if (manifest == null) { - manifest = Manifest() - } + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + if (manifest == null) { + manifest = Manifest() + } - val attributes = manifest!!.mainAttributes + val attributes = manifest!!.mainAttributes - mainClass?.let { - attributes.put(Attributes.Name.MAIN_CLASS, it) - } + mainClass?.let { + attributes.put(Attributes.Name.MAIN_CLASS, it) + } - manifestEntries?.forEach { (key, value) -> - attributes[Attributes.Name(key)] = value - } + manifestEntries?.forEach { (key, value) -> + attributes[Attributes.Name(key)] = value + } - val entry = ZipEntry(JarFile.MANIFEST_NAME).apply { - time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) - } - os.putNextEntry(entry) - manifest!!.write(os) + val entry = ZipEntry(JarFile.MANIFEST_NAME).apply { + time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) } + os.putNextEntry(entry) + manifest!!.write(os) + } - public fun attributes(attributes: Map): ManifestResourceTransformer = apply { - if (manifestEntries == null) { - manifestEntries = mutableMapOf() - } - manifestEntries!!.putAll(attributes.mapValues { Attributes().apply { putValue(it.key, it.value.toString()) } }) + public fun attributes(attributes: Map): ManifestResourceTransformer = apply { + if (manifestEntries == null) { + manifestEntries = mutableMapOf() } + manifestEntries!!.putAll(attributes.mapValues { Attributes().apply { putValue(it.key, it.value.toString()) } }) + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/NoOpTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/NoOpTransformer.kt index 7f793136..4da2796c 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/NoOpTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/NoOpTransformer.kt @@ -4,8 +4,8 @@ import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement public object NoOpTransformer : Transformer { - public override fun canTransformResource(element: FileTreeElement): Boolean = false - public override fun transform(context: TransformerContext): Unit = Unit - public override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean): Unit = Unit - public override fun hasTransformedResource(): Boolean = false + public override fun canTransformResource(element: FileTreeElement): Boolean = false + public override fun transform(context: TransformerContext): Unit = Unit + public override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean): Unit = Unit + public override fun hasTransformedResource(): Boolean = false } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.kt index d4256afd..4f63387b 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.internal.CleanProperties @@ -96,131 +98,130 @@ import org.gradle.api.tasks.Internal * */ public class PropertiesFileTransformer : Transformer { - private val propertiesEntries = mutableMapOf() + private val propertiesEntries = mutableMapOf() - @Input - public var paths: List = listOf() + @Input + public var paths: List = listOf() - @Input - public var mappings: Map> = mapOf() + @Input + public var mappings: Map> = mapOf() - /** - * latest, append - */ - @Input - public var mergeStrategy: String = "first" + /** + * latest, append + */ + @Input + public var mergeStrategy: String = "first" - @Input - public var mergeSeparator: String = "," + @Input + public var mergeSeparator: String = "," - @Input - public var charset: Charset = Charsets.ISO_8859_1 + @Input + public var charset: Charset = Charsets.ISO_8859_1 - @Internal - public var keyTransformer: (String) -> String = defaultKeyTransformer + @Internal + public var keyTransformer: (String) -> String = defaultKeyTransformer - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - if (mappings.containsKey(path)) return true - for (key in mappings.keys) { - if (path.matches(key.toRegex())) return true - } - - if (path in paths) return true - for (p in paths) { - if (path.matches(p.toRegex())) return true - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + if (mappings.containsKey(path)) return true + for (key in mappings.keys) { + if (path.matches(key.toRegex())) return true + } - return mappings.isEmpty() && paths.isEmpty() && path.endsWith(PROPERTIES_SUFFIX) + if (path in paths) return true + for (p in paths) { + if (path.matches(p.toRegex())) return true } - override fun transform(context: TransformerContext) { - val props = propertiesEntries[context.path] - val incoming = loadAndTransformKeys(context.inputStream) - if (props == null) { - propertiesEntries[context.path] = incoming + return mappings.isEmpty() && paths.isEmpty() && path.endsWith(PROPERTIES_SUFFIX) + } + + override fun transform(context: TransformerContext) { + val props = propertiesEntries[context.path] + val incoming = loadAndTransformKeys(context.inputStream) + if (props == null) { + propertiesEntries[context.path] = incoming + } else { + incoming.forEach { (key, value) -> + if (props.containsKey(key)) { + when (mergeStrategyFor(context.path).lowercase()) { + "latest" -> props[key] = value + "append" -> props[key] = props.getProperty(key.toString()) + mergeSeparatorFor(context.path) + value + "first" -> Unit // continue + else -> Unit // continue + } } else { - incoming.forEach { (key, value) -> - if (props.containsKey(key)) { - when (mergeStrategyFor(context.path).lowercase()) { - "latest" -> props[key] = value - "append" -> props[key] = - props.getProperty(key.toString()) + mergeSeparatorFor(context.path) + value - "first" -> Unit // continue - else -> Unit // continue - } - } else { - props[key] = value - } - } + props[key] = value } + } } + } - private fun loadAndTransformKeys(inputStream: InputStream?): CleanProperties { - val props = CleanProperties() - inputStream?.let { - props.load(it.reader(charset)) - } - return transformKeys(props) as CleanProperties + private fun loadAndTransformKeys(inputStream: InputStream?): CleanProperties { + val props = CleanProperties() + inputStream?.let { + props.load(it.reader(charset)) } - - private fun transformKeys(properties: Properties): Properties { - if (keyTransformer == defaultKeyTransformer) return properties - val result = CleanProperties() - properties.forEach { (key, value) -> - result[keyTransformer(key as String)] = value - } - return result + return transformKeys(props) as CleanProperties + } + + private fun transformKeys(properties: Properties): Properties { + if (keyTransformer == defaultKeyTransformer) return properties + val result = CleanProperties() + properties.forEach { (key, value) -> + result[keyTransformer(key as String)] = value } + return result + } - private fun mergeStrategyFor(path: String): String { - mappings[path]?.let { - return it["mergeStrategy"] ?: mergeStrategy - } - for (key in mappings.keys) { - if (path.matches(key.toRegex())) { - return mappings[key]?.get("mergeStrategy") ?: mergeStrategy - } - } - return mergeStrategy + private fun mergeStrategyFor(path: String): String { + mappings[path]?.let { + return it["mergeStrategy"] ?: mergeStrategy } - - private fun mergeSeparatorFor(path: String): String { - mappings[path]?.let { - return it["mergeSeparator"] ?: mergeSeparator - } - for (key in mappings.keys) { - if (path.matches(Regex(key))) { - return mappings[key]?.get("mergeSeparator") ?: mergeSeparator - } - } - return mergeSeparator + for (key in mappings.keys) { + if (path.matches(key.toRegex())) { + return mappings[key]?.get("mergeStrategy") ?: mergeStrategy + } } + return mergeStrategy + } - override fun hasTransformedResource(): Boolean = propertiesEntries.isNotEmpty() - - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val zipWriter = os.writer(charset) - propertiesEntries.forEach { (path, props) -> - val entry = ZipEntry(path) - entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) - os.putNextEntry(entry) - readerFor(props, charset).copyTo(zipWriter) - zipWriter.flush() - os.closeEntry() - } + private fun mergeSeparatorFor(path: String): String { + mappings[path]?.let { + return it["mergeSeparator"] ?: mergeSeparator } - - private fun readerFor(props: Properties, charset: Charset): InputStreamReader { - val baos = ByteArrayOutputStream() - baos.writer(charset).use { writer -> - props.store(writer, "") - } - return baos.toByteArray().inputStream().reader(charset) + for (key in mappings.keys) { + if (path.matches(Regex(key))) { + return mappings[key]?.get("mergeSeparator") ?: mergeSeparator + } } + return mergeSeparator + } + + override fun hasTransformedResource(): Boolean = propertiesEntries.isNotEmpty() + + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val zipWriter = os.writer(charset) + propertiesEntries.forEach { (path, props) -> + val entry = ZipEntry(path) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) + readerFor(props, charset).copyTo(zipWriter) + zipWriter.flush() + os.closeEntry() + } + } - private companion object { - const val PROPERTIES_SUFFIX = ".properties" - val defaultKeyTransformer: (String) -> String = { it } + private fun readerFor(props: Properties, charset: Charset): InputStreamReader { + val baos = ByteArrayOutputStream() + baos.writer(charset).use { writer -> + props.store(writer, "") } + return baos.toByteArray().inputStream().reader(charset) + } + + private companion object { + const val PROPERTIES_SUFFIX = ".properties" + val defaultKeyTransformer: (String) -> String = { it } + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.kt index 3f825e82..d360a785 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.kt @@ -1,3 +1,4 @@ + package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext @@ -15,73 +16,73 @@ import org.gradle.api.tasks.util.PatternSet @CacheableTransformer public class ServiceFileTransformer private constructor( - private val patternSet: PatternSet, + private val patternSet: PatternSet, ) : Transformer, - PatternFilterable by patternSet { - private val serviceEntries = mutableMapOf() + PatternFilterable by patternSet { + private val serviceEntries = mutableMapOf() - public constructor() : this( - PatternSet() - .include(SERVICES_PATTERN) - .exclude(GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN), - ) + public constructor() : this( + PatternSet() + .include(SERVICES_PATTERN) + .exclude(GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN), + ) - public fun setPath(path: String) { - patternSet.setIncludes(listOf("$path/**")) - } + public fun setPath(path: String) { + patternSet.setIncludes(listOf("$path/**")) + } - override fun canTransformResource(element: FileTreeElement): Boolean { - val target = if (element is ShadowCopyAction.ArchiveFileTreeElement) element.asFileTreeElement() else element - return patternSet.asSpec.isSatisfiedBy(target) - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val target = if (element is ShadowCopyAction.ArchiveFileTreeElement) element.asFileTreeElement() else element + return patternSet.asSpec.isSatisfiedBy(target) + } - override fun transform(context: TransformerContext) { - val lines = context.inputStream.bufferedReader().readLines().toMutableList() - var targetPath = context.path - context.relocators.forEach { rel -> - if (rel.canRelocateClass(File(targetPath).name)) { - targetPath = rel.relocateClass(RelocateClassContext(targetPath, context.stats)) - } - lines.forEachIndexed { i, line -> - if (rel.canRelocateClass(line)) { - val lineContext = RelocateClassContext(line, context.stats) - lines[i] = rel.relocateClass(lineContext) - } - } - } - lines.forEach { line -> - serviceEntries.getOrPut(targetPath) { ServiceStream() }.append(line.toByteArray().inputStream()) + override fun transform(context: TransformerContext) { + val lines = context.inputStream.bufferedReader().readLines().toMutableList() + var targetPath = context.path + context.relocators.forEach { rel -> + if (rel.canRelocateClass(File(targetPath).name)) { + targetPath = rel.relocateClass(RelocateClassContext(targetPath, context.stats)) + } + lines.forEachIndexed { i, line -> + if (rel.canRelocateClass(line)) { + val lineContext = RelocateClassContext(line, context.stats) + lines[i] = rel.relocateClass(lineContext) } + } } - - override fun hasTransformedResource(): Boolean = serviceEntries.isNotEmpty() - - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - serviceEntries.forEach { (path, stream) -> - val entry = ZipEntry(path) - entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) - os.putNextEntry(entry) - stream.toInputStream().copyTo(os) - os.closeEntry() - } + lines.forEach { line -> + serviceEntries.getOrPut(targetPath) { ServiceStream() }.append(line.toByteArray().inputStream()) } + } - public class ServiceStream : ByteArrayOutputStream(1024) { - @Throws(IOException::class) - public fun append(inputStream: InputStream) { - if (count > 0 && buf[count - 1] != '\n'.code.toByte() && buf[count - 1] != '\r'.code.toByte()) { - val newline = "\n".toByteArray() - write(newline, 0, newline.size) - } - inputStream.copyTo(this) - } + override fun hasTransformedResource(): Boolean = serviceEntries.isNotEmpty() - public fun toInputStream(): InputStream = ByteArrayInputStream(buf, 0, count) + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + serviceEntries.forEach { (path, stream) -> + val entry = ZipEntry(path) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) + stream.toInputStream().copyTo(os) + os.closeEntry() } + } - private companion object { - const val SERVICES_PATTERN = "META-INF/services/**" - const val GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN = - "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" + public class ServiceStream : ByteArrayOutputStream(1024) { + @Throws(IOException::class) + public fun append(inputStream: InputStream) { + if (count > 0 && buf[count - 1] != '\n'.code.toByte() && buf[count - 1] != '\r'.code.toByte()) { + val newline = "\n".toByteArray() + write(newline, 0, newline.size) + } + inputStream.copyTo(this) } + + public fun toInputStream(): InputStream = ByteArrayInputStream(buf, 0, count) + } + + private companion object { + const val SERVICES_PATTERN = "META-INF/services/**" + const val GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN = + "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Transformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Transformer.kt index 0e2f6179..7341ac0c 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Transformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Transformer.kt @@ -1,3 +1,4 @@ + package com.github.jengelman.gradle.plugins.shadow.transformers import org.apache.tools.zip.ZipOutputStream @@ -13,14 +14,14 @@ import org.gradle.api.tasks.Internal * @author John Engelman */ public interface Transformer : Named { - public fun canTransformResource(element: FileTreeElement): Boolean + public fun canTransformResource(element: FileTreeElement): Boolean - public fun transform(context: TransformerContext) + public fun transform(context: TransformerContext) - public fun hasTransformedResource(): Boolean + public fun hasTransformedResource(): Boolean - public fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) + public fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) - @Internal - override fun getName(): String = this::class.java.simpleName + @Internal + override fun getName(): String = this::class.java.simpleName } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerContext.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerContext.kt index 94d54ac8..b5a8cf86 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerContext.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerContext.kt @@ -6,39 +6,39 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction import java.io.InputStream public data class TransformerContext( - val path: String, - val inputStream: InputStream, - val relocators: List, - val stats: ShadowStats, + val path: String, + val inputStream: InputStream, + val relocators: List, + val stats: ShadowStats, ) { - public class Builder { - private var path: String? = null - private var inputStream: InputStream? = null - private var relocators: List? = null - private var stats: ShadowStats? = null + public class Builder { + private var path: String? = null + private var inputStream: InputStream? = null + private var relocators: List? = null + private var stats: ShadowStats? = null - public fun path(path: String): Builder = apply { this.path = path } - public fun inputStream(inputStream: InputStream): Builder = apply { this.inputStream = inputStream } - public fun relocators(relocators: List): Builder = apply { this.relocators = relocators } - public fun stats(stats: ShadowStats): Builder = apply { this.stats = stats } + public fun path(path: String): Builder = apply { this.path = path } + public fun inputStream(inputStream: InputStream): Builder = apply { this.inputStream = inputStream } + public fun relocators(relocators: List): Builder = apply { this.relocators = relocators } + public fun stats(stats: ShadowStats): Builder = apply { this.stats = stats } - public fun build(): TransformerContext { - return TransformerContext( - requireNotNull(path), - requireNotNull(inputStream), - requireNotNull(relocators), - requireNotNull(stats), - ) - } + public fun build(): TransformerContext { + return TransformerContext( + requireNotNull(path), + requireNotNull(inputStream), + requireNotNull(relocators), + requireNotNull(stats), + ) } + } - public companion object { - @JvmStatic - public fun getEntryTimestamp(preserveFileTimestamps: Boolean, entryTime: Long): Long { - return if (preserveFileTimestamps) entryTime else ShadowCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES - } - - @JvmStatic - public fun builder(): Builder = Builder() + public companion object { + @JvmStatic + public fun getEntryTimestamp(preserveFileTimestamps: Boolean, entryTime: Long): Long { + return if (preserveFileTimestamps) entryTime else ShadowCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES } + + @JvmStatic + public fun builder(): Builder = Builder() + } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.kt index e667cd9e..9879789e 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.kt @@ -1,3 +1,5 @@ + + package com.github.jengelman.gradle.plugins.shadow.transformers import java.io.StringReader @@ -18,61 +20,61 @@ import org.xml.sax.InputSource @CacheableTransformer public class XmlAppendingTransformer : Transformer { - @Input - public var ignoreDtd: Boolean = true + @Input + public var ignoreDtd: Boolean = true - @Optional - @Input - public var resource: String? = null + @Optional + @Input + public var resource: String? = null - private var doc: Document? = null + private var doc: Document? = null - override fun canTransformResource(element: FileTreeElement): Boolean { - val path = element.relativePath.pathString - return resource?.equals(path, ignoreCase = true) == true - } + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return resource?.equals(path, ignoreCase = true) == true + } - override fun transform(context: TransformerContext) { - val r: Document - try { - val builder = SAXBuilder(XMLReaders.NONVALIDATING).apply { - expandEntities = false - if (ignoreDtd) { - entityResolver = EntityResolver { _, _ -> InputSource(StringReader("")) } - } - } - r = builder.build(context.inputStream) - } catch (e: JDOMException) { - throw RuntimeException("Error processing resource $resource: ${e.message}", e) + override fun transform(context: TransformerContext) { + val r: Document + try { + val builder = SAXBuilder(XMLReaders.NONVALIDATING).apply { + expandEntities = false + if (ignoreDtd) { + entityResolver = EntityResolver { _, _ -> InputSource(StringReader("")) } } + } + r = builder.build(context.inputStream) + } catch (e: JDOMException) { + throw RuntimeException("Error processing resource $resource: ${e.message}", e) + } - if (doc == null) { - doc = r - } else { - val root = r.rootElement - - root.attributes.forEach { a -> - val mergedEl = doc!!.rootElement - val mergedAtt = mergedEl.getAttribute(a.name, a.namespace) - if (mergedAtt == null) { - mergedEl.setAttribute(a) - } - } + if (doc == null) { + doc = r + } else { + val root = r.rootElement - root.children.forEach { n -> - doc!!.rootElement.addContent(n.clone()) - } + root.attributes.forEach { a -> + val mergedEl = doc!!.rootElement + val mergedAtt = mergedEl.getAttribute(a.name, a.namespace) + if (mergedAtt == null) { + mergedEl.setAttribute(a) } + } + + root.children.forEach { n -> + doc!!.rootElement.addContent(n.clone()) + } } + } - override fun hasTransformedResource(): Boolean = doc != null + override fun hasTransformedResource(): Boolean = doc != null - override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val entry = ZipEntry(resource).apply { - time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) - } - os.putNextEntry(entry) - XMLOutputter(Format.getPrettyFormat()).output(doc, os) - doc = null + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val entry = ZipEntry(resource).apply { + time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, time) } + os.putNextEntry(entry) + XMLOutputter(Format.getPrettyFormat()).output(doc, os) + doc = null + } }