Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import java.io.ByteArrayOutputStream
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.file.FileTreeElement
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional

/**
* A resource processor that appends content for a resource, separated by a newline.
*
* Modified from `org.apache.maven.plugins.shade.resource.AppendingTransformer.java`
*
* Modifications
* @author John Engelman
*/
@CacheableTransformer
@Suppress("ktlint:standard:backing-property-naming")
open class AppendingTransformer : Transformer {
/**
* Defer initialization, see [issue 763](https://github.com/GradleUp/shadow/issues/763).
*/
private var _data: ByteArrayOutputStream? = null
private inline val data get() = if (_data == null) ByteArrayOutputStream().also { _data = it } else _data!!

@get:Optional
@get:Input
var resource: String? = null

override fun canTransformResource(element: FileTreeElement): Boolean {
return resource.equals(element.relativePath.pathString, ignoreCase = true)
}

override fun transform(context: TransformerContext) {
context.inputStream.use {
it.copyTo(data)
data.write('\n'.code)
}
}

override fun hasTransformedResource(): Boolean {
return data.size() > 0
}

override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
val entry = ZipEntry(requireNotNull(resource))
entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time)
os.putNextEntry(entry)

data.toByteArray().inputStream().copyTo(os)
data.reset()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import java.io.ByteArrayOutputStream
import java.io.IOException
import java.util.jar.JarFile.MANIFEST_NAME
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.file.FileTreeElement
import org.gradle.api.tasks.Input
import org.slf4j.LoggerFactory

/**
* A resource processor that can append arbitrary attributes to the first MANIFEST.MF
* that is found in the set of JARs being processed. The attributes are appended in
* the specified order, and duplicates are allowed.
*
* Modified from [ManifestResourceTransformer].
* @author Chris Rankin
*/
open class ManifestAppenderTransformer : Transformer {
private var manifestContents = ByteArray(0)
private val _attributes = mutableListOf<Pair<String, Comparable<*>>>()

@get:Input
open val attributes: List<Pair<String, Comparable<*>>> get() = _attributes

override fun canTransformResource(element: FileTreeElement): Boolean {
return MANIFEST_NAME.equals(element.relativePath.pathString, ignoreCase = true)
}

override fun transform(context: TransformerContext) {
if (manifestContents.isEmpty()) {
try {
context.inputStream.use { inputStream ->
val outputStream = ByteArrayOutputStream()
inputStream.copyTo(outputStream)
manifestContents = outputStream.toByteArray()
}
} catch (e: IOException) {
logger.warn("Failed to read MANIFEST.MF", e)
}
}
}

override fun hasTransformedResource(): Boolean = _attributes.isNotEmpty()

override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
val entry = ZipEntry(MANIFEST_NAME)
entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time)
os.putNextEntry(entry)
os.write(manifestContents)

if (_attributes.isNotEmpty()) {
for ((key, value) in _attributes) {
os.write(key.toByteArray())
os.write(SEPARATOR)
os.write(value.toString().toByteArray())
os.write(EOL)
}
os.write(EOL)
_attributes.clear()
}
}

open fun append(name: String, value: Comparable<*>): ManifestAppenderTransformer = apply {
_attributes.add(Pair(name, value))
}

private companion object {
private val logger = LoggerFactory.getLogger(ManifestAppenderTransformer::class.java)
private val EOL = "\r\n".toByteArray()
private val SEPARATOR = ": ".toByteArray()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext.Companion.getEntryTimestamp
import java.io.IOException
import java.util.jar.Attributes
import java.util.jar.JarFile
import java.util.jar.Manifest
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.file.FileTreeElement
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.slf4j.LoggerFactory

/**
* A resource processor that allows the arbitrary addition of attributes to
* the first MANIFEST.MF that is found in the set of JARs being processed, or
* to a newly created manifest for the shaded JAR.
*
* Modified from `org.apache.maven.plugins.shade.resource.ManifestResourceTransformer`
*
* @author Jason van Zyl
* @author John Engelman
*/
open class ManifestResourceTransformer : Transformer {
private var manifestDiscovered = false
private var manifest: Manifest? = null

@get:Optional
@get:Input
var mainClass: String? = null

@get:Optional
@get:Input
var manifestEntries: MutableMap<String, Attributes>? = null

override fun canTransformResource(element: FileTreeElement): Boolean {
val path = element.relativePath.pathString
return JarFile.MANIFEST_NAME.equals(path, ignoreCase = true)
}

override fun transform(context: TransformerContext) {
// We just want to take the first manifest we come across as that's our project's manifest. This is the behavior
// now which is situational at best. Right now there is no context passed in with the processing so we cannot
// tell what artifact is being processed.
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 modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
// If we didn't find a manifest, then let's create one.
if (manifest == null) {
manifest = Manifest()
}

val attributes = manifest!!.mainAttributes
mainClass?.let {
attributes[Attributes.Name.MAIN_CLASS] = it
}
manifestEntries?.forEach { (key, value) ->
attributes[Attributes.Name(key)] = value
}

val entry = ZipEntry(JarFile.MANIFEST_NAME)
entry.time = getEntryTimestamp(preserveFileTimestamps, entry.time)
os.putNextEntry(entry)
manifest!!.write(os)
}

open fun attributes(attributes: Map<String, Attributes>): ManifestResourceTransformer = apply {
if (manifestEntries == null) {
manifestEntries = LinkedHashMap()
}
manifestEntries!!.putAll(attributes)
}

private companion object {
private val logger = LoggerFactory.getLogger(ManifestResourceTransformer::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import java.io.StringReader
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.file.FileTreeElement
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.jdom2.Document
import org.jdom2.JDOMException
import org.jdom2.input.SAXBuilder
import org.jdom2.input.sax.XMLReaders
import org.jdom2.output.Format
import org.jdom2.output.XMLOutputter
import org.xml.sax.EntityResolver
import org.xml.sax.InputSource

/**
* Appends multiple occurrences of some XML file.
*
* Modified from `org.apache.maven.plugins.shade.resource.XmlAppendingTransformer.java`
*
* @author John Engelman
*/
@CacheableTransformer
open class XmlAppendingTransformer : Transformer {
private var doc: Document? = null

@get:Input
var ignoreDtd: Boolean = true

@get:Optional
@get:Input
var resource: String? = null

override fun canTransformResource(element: FileTreeElement): Boolean {
return resource?.equals(element.relativePath.pathString, ignoreCase = true) == true
}

override fun transform(context: TransformerContext) {
val r = try {
SAXBuilder(XMLReaders.NONVALIDATING).apply {
expandEntities = false
if (ignoreDtd) {
entityResolver = EntityResolver { _, _ -> InputSource(StringReader("")) }
}
}.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)
}
}
root.children.forEach { n ->
doc!!.rootElement.addContent(n.clone())
}
}
}

override fun hasTransformedResource(): Boolean = doc != null

override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
val entry = ZipEntry(resource)
entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time)
os.putNextEntry(entry)
XMLOutputter(Format.getPrettyFormat()).output(doc, os)
doc = null
}

companion object {
const val XSI_NS: String = "http://www.w3.org/2001/XMLSchema-instance"
}
}

This file was deleted.

Loading