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,72 @@
package com.github.jengelman.gradle.plugins.shadow

import org.gradle.api.GradleException

open class ShadowStats {
open var totalTime: Long = 0
open var jarStartTime: Long = 0
open var jarEndTime: Long = 0
open var jarCount: Int = 1
open var processingJar: Boolean = false
open val relocations: MutableMap<String, String> = mutableMapOf()

open val relocationString: String
get() {
return relocations.map { (k, v) -> "$k → $v" }
.sorted()
.joinToString("\n")
}

open val jarTiming: Long
get() = jarEndTime - jarStartTime

open val totalTimeSecs: Double
get() = totalTime / 1000.0

open val averageTimePerJar: Double
get() = totalTime / jarCount.toDouble()

open val averageTimeSecsPerJar: Double
get() = averageTimePerJar / 1000.0

open val buildScanData: Map<String, String>
get() = mapOf(
"dependencies" to jarCount.toString(),
"relocations" to relocationString,
)

open fun relocate(src: String, dst: String) {
relocations[src] = dst
}

open fun startJar() {
if (processingJar) throw GradleException("Can only time one entry at a time")
processingJar = true
jarStartTime = System.currentTimeMillis()
}

open fun finishJar() {
if (processingJar) {
jarEndTime = System.currentTimeMillis()
jarCount++
totalTime += jarTiming
processingJar = false
}
}

open fun printStats() {
println(this)
}

override fun toString(): String {
return """
*******************
GRADLE SHADOW STATS

Total Jars: $jarCount (includes project)
Total Time: ${totalTimeSecs}s [${totalTime}ms]
Average Time/Jar: ${averageTimeSecsPerJar}s [${averageTimePerJar}ms]
*******************
""".trimIndent()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.github.jengelman.gradle.plugins.shadow.internal

import java.io.BufferedWriter
import java.io.IOException
import java.io.Writer
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)
}

private class StripCommentsWithTimestampBufferedWriter(out: Writer) : BufferedWriter(out) {
private val lengthOfExpectedTimestamp = ("#" + Date().toString()).length

@Throws(IOException::class)
override fun write(str: String) {
if (str.couldBeCommentWithTimestamp) return
super.write(str)
}

private val String?.couldBeCommentWithTimestamp: Boolean get() {
return this != null && startsWith("#") && length == lengthOfExpectedTimestamp
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.github.jengelman.gradle.plugins.shadow.internal

import com.github.jengelman.gradle.plugins.shadow.tasks.ZipCompressor
import java.io.File
import org.apache.tools.zip.Zip64Mode
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.UncheckedIOException

internal class DefaultZipCompressor(
allowZip64Mode: Boolean,
private val entryCompressionMethod: Int,
) : ZipCompressor {
private val 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)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.jengelman.gradle.plugins.shadow.tasks

import org.gradle.api.internal.file.archive.compression.ArchiveOutputStreamFactory

interface ZipCompressor : ArchiveOutputStreamFactory
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import org.gradle.api.file.FileTreeElement

/**
* Prevents duplicate copies of the license
*
* Modified from `org.apache.maven.plugins.shade.resouce.ApacheLicenseResourceTransformer.java`
*
* @author John Engelman
*/
open 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)
}

private companion object {
private const val LICENSE_PATH = "META-INF/LICENSE"
private const val LICENSE_TXT_PATH = "META-INF/LICENSE.txt"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import org.gradle.api.file.FileTreeElement
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional

/**
* A resource processor that prevents the inclusion of an arbitrary resource into the shaded JAR.
*
* Modified from `org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer.java`
*
* @author John Engelman
*/
open class DontIncludeResourceTransformer : Transformer by NoOpTransformer {
@get:Optional
@get:Input
var resource: String? = null

override fun canTransformResource(element: FileTreeElement): Boolean {
val path = element.relativePath.pathString
return !resource.isNullOrEmpty() && path.endsWith(resource!!)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext.Companion.getEntryTimestamp
import java.io.File
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity

/**
* A resource processor that allows the addition of an arbitrary file
* content into the shaded JAR.
*
* Modified from `org.apache.maven.plugins.shade.resource.IncludeResourceTransformer.java`
*
* @author John Engelman
*/
open class IncludeResourceTransformer : Transformer by NoOpTransformer {
@get:InputFile
@get:PathSensitive(PathSensitivity.NONE)
var file: File? = null

@get:Input
var resource: String? = null

override fun hasTransformedResource(): Boolean = file?.exists() == true

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

requireNotNull(file).inputStream().use { inputStream ->
inputStream.copyTo(os)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.github.jengelman.gradle.plugins.shadow.transformers

import com.github.jengelman.gradle.plugins.shadow.ShadowStats
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction
import java.io.InputStream
import java.util.GregorianCalendar

data class TransformerContext @JvmOverloads constructor(
val path: String,
val inputStream: InputStream,
val relocators: List<Relocator> = emptyList(),
val stats: ShadowStats = ShadowStats(),
) {
class Builder {
private var path = ""
private var inputStream: InputStream? = null
private var relocators = emptyList<Relocator>()
private var stats = ShadowStats()

fun path(path: String): Builder = apply { this.path = path }
fun inputStream(inputStream: InputStream): Builder = apply { this.inputStream = inputStream }
fun relocators(relocators: List<Relocator>): Builder = apply { this.relocators = relocators }
fun stats(stats: ShadowStats): Builder = apply { this.stats = stats }
fun build(): TransformerContext = TransformerContext(
path = path,
inputStream = inputStream ?: error("inputStream is required"),
relocators = relocators,
stats = stats,
)
}

companion object {
/**
* TODO: replace this with [ShadowCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES]
*/
private val CONSTANT_TIME_FOR_ZIP_ENTRIES = GregorianCalendar(1980, 1, 1, 0, 0, 0).getTimeInMillis()

@JvmStatic
fun builder(): Builder = Builder()

@JvmStatic
fun getEntryTimestamp(preserveFileTimestamps: Boolean, entryTime: Long): Long {
return if (preserveFileTimestamps) entryTime else CONSTANT_TIME_FOR_ZIP_ENTRIES
}
}
}

This file was deleted.

This file was deleted.

Loading