1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 00:17:11 -07:00

Use commons-compress fast archive.

This commit is contained in:
Cedric Beust 2017-04-11 15:58:52 -07:00
parent 46f73ee5e7
commit c195a7bdf7
5 changed files with 101 additions and 56 deletions

View file

@ -6,13 +6,12 @@ import com.beust.kobalt.archive.Archives
import com.beust.kobalt.archive.Zip import com.beust.kobalt.archive.Zip
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.Scope import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.misc.* import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog
import com.google.inject.Inject import com.google.inject.Inject
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.OutputStream
import java.nio.file.Paths import java.nio.file.Paths
import java.util.jar.JarOutputStream
import java.util.jar.Manifest import java.util.jar.Manifest
class JarGenerator @Inject constructor(val dependencyManager: DependencyManager) : ArchiveGenerator { class JarGenerator @Inject constructor(val dependencyManager: DependencyManager) : ArchiveGenerator {
@ -155,10 +154,8 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
} }
} }
val jarFactory = { os: OutputStream -> JarOutputStream(os, manifest) }
return Archives.generateArchive(project, context, zip.name, ".jar", includedFiles, return Archives.generateArchive(project, context, zip.name, ".jar", includedFiles,
true /* expandJarFiles */, jarFactory) true /* expandJarFiles */, manifest)
} }
} }

View file

@ -8,10 +8,7 @@ import com.beust.kobalt.misc.JarUtils
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.kobaltLog
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
import java.util.* import java.util.*
import java.util.zip.ZipOutputStream
class Archives { class Archives {
companion object { companion object {
@ -20,8 +17,6 @@ class Archives {
@ExportedProjectProperty(doc = "The name of the a jar file with a main() method", type = "String") @ExportedProjectProperty(doc = "The name of the a jar file with a main() method", type = "String")
const val JAR_NAME_WITH_MAIN_CLASS = "jarNameWithMainClass" const val JAR_NAME_WITH_MAIN_CLASS = "jarNameWithMainClass"
private val DEFAULT_STREAM_FACTORY = { os : OutputStream -> ZipOutputStream(os) }
fun defaultArchiveName(project: Project) = project.name + "-" + project.version fun defaultArchiveName(project: Project) = project.name + "-" + project.version
fun generateArchive(project: Project, fun generateArchive(project: Project,
@ -30,15 +25,15 @@ class Archives {
suffix: String, suffix: String,
includedFiles: List<IncludedFile>, includedFiles: List<IncludedFile>,
expandJarFiles : Boolean = false, expandJarFiles : Boolean = false,
outputStreamFactory: (OutputStream) -> ZipOutputStream = DEFAULT_STREAM_FACTORY) : File { manifest: java.util.jar.Manifest? = null) : File {
val fullArchiveName = context.variant.archiveName(project, archiveName, suffix) val fullArchiveName = context.variant.archiveName(project, archiveName, suffix)
val archiveDir = File(KFiles.libsDir(project)) val archiveDir = File(KFiles.libsDir(project))
val result = File(archiveDir.path, fullArchiveName) val result = File(archiveDir.path, fullArchiveName)
context.logger.log(project.name, 3, "Creating $result") context.logger.log(project.name, 3, "Creating $result")
if (! Features.USE_TIMESTAMPS || isOutdated(project.directory, includedFiles, result)) { if (! Features.USE_TIMESTAMPS || isOutdated(project.directory, includedFiles, result)) {
try { try {
outputStreamFactory(FileOutputStream(result)).use { MetaArchive(result, manifest).use { metaArchive ->
JarUtils.addFiles(project.directory, includedFiles, it, expandJarFiles) JarUtils.addFiles(project.directory, includedFiles, metaArchive, expandJarFiles)
context.logger.log(project.name, 2, "Added ${includedFiles.size} files to $result") context.logger.log(project.name, 2, "Added ${includedFiles.size} files to $result")
context.logger.log(project.name, 1, " Created $result") context.logger.log(project.name, 1, " Created $result")
} }

View file

@ -0,0 +1,74 @@
package com.beust.kobalt.archive
import com.beust.kobalt.Glob
import com.beust.kobalt.misc.KFiles
import org.apache.commons.compress.archivers.ArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
import java.io.Closeable
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import org.apache.commons.compress.archivers.zip.ZipFile as ApacheZipFile
/**
* Abstraction of a zip/jar/war archive that automatically manages the addition of expanded jar files.
* Uses ZipArchiveOutputStream for fast inclusion of expanded jar files.
*/
class MetaArchive(outputFile: File, val manifest: java.util.jar.Manifest?) : Closeable {
private val zos = ZipArchiveOutputStream(outputFile).apply {
encoding = "UTF-8"
}
fun addFile(file: File, path: String) {
FileInputStream(file).use { inputStream ->
val entry = zos.createArchiveEntry(file, path)
maybeAddEntry(entry) {
addEntry(entry, inputStream)
}
}
}
fun addArchive(jarFile: File) {
ApacheZipFile(jarFile).use { jar ->
val jarEntries = jar.entries
for (entry in jarEntries) {
maybeAddEntry(entry) {
zos.addRawArchiveEntry(entry, jar.getRawInputStream(entry))
}
}
}
}
private val DEFAULT_JAR_EXCLUDES =
Glob("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA")
private val seen = hashSetOf<String>()
private fun okToAdd(name: String): Boolean = ! seen.contains(name)
&& ! KFiles.isExcluded(name, DEFAULT_JAR_EXCLUDES)
override fun close() {
if (manifest != null) {
val manifestFile = Files.createTempFile("aaa", "bbb").toFile()
manifest.write(FileOutputStream(manifestFile))
val entry = zos.createArchiveEntry(manifestFile, "META-INF/MANIFEST.MF")
addEntry(entry, FileInputStream(manifestFile))
}
zos.close()
}
private fun addEntry(entry: ArchiveEntry, inputStream: FileInputStream) {
zos.putArchiveEntry(entry)
inputStream.copyTo(zos, 50 * 1024)
zos.closeArchiveEntry()
}
private fun maybeAddEntry(entry: ArchiveEntry, action:() -> Unit) {
if (okToAdd(entry.name)) {
action()
}
seen.add(entry.name)
}
}

View file

@ -1,14 +1,16 @@
package com.beust.kobalt.misc package com.beust.kobalt.misc
import com.beust.kobalt.* import com.beust.kobalt.From
import com.beust.kobalt.IFileSpec
import com.beust.kobalt.IncludedFile
import com.beust.kobalt.To
import com.beust.kobalt.archive.MetaArchive
import com.google.common.io.CharStreams import com.google.common.io.CharStreams
import java.io.* import java.io.File
import java.util.jar.JarEntry import java.io.FileOutputStream
import java.io.InputStreamReader
import java.util.jar.JarFile import java.util.jar.JarFile
import java.util.jar.JarInputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
class JarUtils { class JarUtils {
companion object { companion object {
@ -19,18 +21,15 @@ class JarUtils {
} }
} }
fun addFiles(directory: String, files: List<IncludedFile>, target: ZipOutputStream, fun addFiles(directory: String, files: List<IncludedFile>, metaArchive: MetaArchive,
expandJarFiles: Boolean, expandJarFiles: Boolean,
onError: (Exception) -> Unit = DEFAULT_HANDLER) { onError: (Exception) -> Unit = DEFAULT_HANDLER) {
files.forEach { files.forEach {
addSingleFile(directory, it, target, expandJarFiles, onError) addSingleFile(directory, it, metaArchive, expandJarFiles, onError)
} }
} }
private val DEFAULT_JAR_EXCLUDES = fun addSingleFile(directory: String, file: IncludedFile, metaArchive: MetaArchive,
Glob("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA")
fun addSingleFile(directory: String, file: IncludedFile, outputStream: ZipOutputStream,
expandJarFiles: Boolean, onError: (Exception) -> Unit = DEFAULT_HANDLER) { expandJarFiles: Boolean, onError: (Exception) -> Unit = DEFAULT_HANDLER) {
val foundFiles = file.allFromFiles(directory) val foundFiles = file.allFromFiles(directory)
foundFiles.forEach { foundFile -> foundFiles.forEach { foundFile ->
@ -49,42 +48,22 @@ class JarUtils {
// Directory // Directory
val includedFile = IncludedFile(From(""), To(""), listOf(IFileSpec.GlobSpec("**"))) val includedFile = IncludedFile(From(""), To(""), listOf(IFileSpec.GlobSpec("**")))
addSingleFile(localFile.path, includedFile, outputStream, expandJarFiles) addSingleFile(localFile.path, includedFile, metaArchive, expandJarFiles)
} else { } else {
if (file.expandJarFiles && foundFile.name.endsWith(".jar") && ! file.from.contains("resources")) { try {
kobaltLog(2, " Writing contents of jar file $foundFile") if (file.expandJarFiles && foundFile.name.endsWith(".jar") && !file.from.contains("resources")) {
JarInputStream(FileInputStream(localFile)).use { stream -> kobaltLog(2, " Writing contents of jar file $foundFile")
var entry = stream.nextEntry metaArchive.addArchive(foundFile)
while (entry != null) { } else {
if (!entry.isDirectory && !KFiles.isExcluded(entry.name, DEFAULT_JAR_EXCLUDES)) { metaArchive.addFile(File(directory, fromFile.path), foundFile.path)
addEntry(stream, JarEntry(entry), outputStream, onError)
}
entry = stream.nextEntry
}
}
} else {
val entryFileName = KFiles.fixSlashes(file.to(foundFile.path))
val entry = JarEntry(entryFileName)
entry.time = localFile.lastModified()
FileInputStream(localFile).use { stream ->
addEntry(stream, entry, outputStream, onError)
} }
} catch(ex: Exception) {
onError(ex)
} }
} }
} }
} }
private fun addEntry(inputStream: InputStream, entry: ZipEntry, outputStream: ZipOutputStream,
onError: (Exception) -> Unit = DEFAULT_HANDLER) {
try {
outputStream.putNextEntry(entry)
inputStream.copyTo(outputStream, 50 * 1024)
outputStream.closeEntry()
} catch(ex: Exception) {
onError(ex)
}
}
fun extractTextFile(zip : ZipFile, fileName: String) : String? { fun extractTextFile(zip : ZipFile, fileName: String) : String? {
val enumEntries = zip.entries() val enumEntries = zip.entries()
while (enumEntries.hasMoreElements()) { while (enumEntries.hasMoreElements()) {

View file

@ -88,7 +88,7 @@ class WarGenerator @Inject constructor(val dependencyManager: DependencyManager,
val jarFactory = { os: OutputStream -> JarOutputStream(os, manifest) } val jarFactory = { os: OutputStream -> JarOutputStream(os, manifest) }
return Archives.generateArchive(project, context, war.name, ".war", files, return Archives.generateArchive(project, context, war.name, ".war", files,
false /* don't expand jar files */, jarFactory) false /* don't expand jar files */, manifest)
} }
} }