aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrockjam <5min4eq.unity@gmail.com>2016-06-24 06:57:11 +0300
committerrockjam <5min4eq.unity@gmail.com>2016-06-24 07:27:36 +0300
commite709c5f02290680cd05c18e470b57decb931e62d (patch)
tree63d5015ff71cb464dbb430ffeff5caec304a1001
parent9768c740095672aaad55309ec9b1ce88f7f840be (diff)
downloadcbt-e709c5f02290680cd05c18e470b57decb931e62d.tar.gz
cbt-e709c5f02290680cd05c18e470b57decb931e62d.tar.bz2
cbt-e709c5f02290680cd05c18e470b57decb931e62d.zip
update uber jar PR
-rw-r--r--examples/uber-jar-example/build/build.scala2
-rw-r--r--plugins/uber-jar/src/UberJar.scala137
-rw-r--r--plugins/uber-jar/src/uberjar/JarUtils.scala67
-rw-r--r--plugins/uber-jar/src/uberjar/TryWithResources.scala13
-rw-r--r--stage2/Lib.scala16
5 files changed, 66 insertions, 169 deletions
diff --git a/examples/uber-jar-example/build/build.scala b/examples/uber-jar-example/build/build.scala
index fca7737..a36e27b 100644
--- a/examples/uber-jar-example/build/build.scala
+++ b/examples/uber-jar-example/build/build.scala
@@ -1,6 +1,6 @@
import cbt._
-class Build(val context: Context) extends BuildBuild with UberJar {
+class Build(val context: Context) extends BaseBuild with UberJar {
override def projectName: String = "uber-jar-example"
diff --git a/plugins/uber-jar/src/UberJar.scala b/plugins/uber-jar/src/UberJar.scala
index a26053a..473556f 100644
--- a/plugins/uber-jar/src/UberJar.scala
+++ b/plugins/uber-jar/src/UberJar.scala
@@ -1,36 +1,17 @@
package cbt
-import java.io.{File, FileOutputStream}
-import java.nio.file._
-import java.util.jar
-import java.util.jar.JarOutputStream
+import java.io.File
+import java.nio.file.{Files, Path}
import cbt.uberjar._
-import scala.util.{Failure, Success, Try}
-
trait UberJar extends BaseBuild {
- private val log: String => Unit = logger.log("uber-jar", _)
-
final def uberJar: ExitCode = {
- // we need compile first to produce target directory
- compile
System.err.println("Creating uber jar...")
- UberJar.createUberJar(
- targetDir = target,
- compilerTarget = compileTarget,
- classpath = classpath,
- mainClass = uberJarMainClass,
- jarName = uberJarName
- )(log) match {
- case Success(_) =>
- System.err.println("Creating uber jar - DONE")
- ExitCode.Success
- case Failure(e) =>
- System.err.println(s"Failed to create uber jar, cause: $e")
- ExitCode.Failure
- }
+ new UberJarLib(logger).create(target, compileTarget, classpath, uberJarMainClass, uberJarName)
+ System.err.println("Creating uber jar - DONE")
+ ExitCode.Success
}
def uberJarMainClass: Option[String] = Some(runClass)
@@ -39,98 +20,46 @@ trait UberJar extends BaseBuild {
}
-object UberJar extends JarUtils {
- import TryWithResources._
+class UberJarLib(logger: Logger) extends JarUtils {
+ private val log: String => Unit = logger.log("uber-jar", _)
+ private val lib = new cbt.Lib(logger)
/**
* Creates uber jar for given build.
- * Uber jar construction steps:
- * 1. create jar file with our customized MANIFEST.MF
- * 2. write files from `compilerTarget` to jar file
- * 3. get all jars from `classpath`
- * 4. extract all jars, filter out their MANIFEST.MF and signatures files
- * 5. write content of all jars to target jar file
- * 6. Finalize everything, and return `ExitCode`
*
- * @param targetDir build's target directory
- * @param compilerTarget directory where compiled classfiles are
- * @param classpath build's classpath
- * @param mainClass main class name(optional)
- * @param jarName name of resulting jar file
- * @param log logger
- * @return `ExitCode.Success` if uber jar created and `ExitCode.Failure` otherwise
+ * @param target build's target directory
+ * @param compileTarget directory where compiled classfiles are
+ * @param classpath build's classpath
+ * @param jarName name of resulting jar file
*/
- def createUberJar(targetDir: File,
- compilerTarget: File,
- classpath: ClassPath,
- mainClass: Option[String],
- jarName: String
- )(log: String => Unit): Try[Unit] = {
- val targetPath = targetDir.toPath
- log(s"Target directory is: $targetPath")
- log(s"Compiler targer directory is: $compilerTarget")
+ def create(target: File,
+ compileTarget: File,
+ classpath: ClassPath,
+ mainClass: Option[String],
+ jarName: String): Unit = {
+ log(s"Compiler target directory is: $compileTarget")
log(s"Classpath is: $classpath")
+ log(s"Target directory is: $target")
mainClass foreach (c => log(s"Main class is is: $c"))
- val jarPath = {
- log("Creating jar file...")
- val validJarName = if (jarName.endsWith("*.jar")) jarName else jarName + ".jar"
- log(s"Jar name is: $validJarName")
- val path = targetPath.resolve(validJarName)
- Files.deleteIfExists(path)
- Files.createFile(path)
- log("Creating jar file - DONE")
- path
- }
- withCloseable(new JarOutputStream(new FileOutputStream(jarPath.toFile), createManifest(mainClass))) { out =>
- writeTarget(compilerTarget, out)(log)
+ log("Creating far file...")
+ val file = createJarFile(target.toPath, jarName)
+ log("Creating far file - DONE")
- // it will contain all jar files, including jars, that cbt depend on! Not good!
- val jars = classpath.files filter (f => jarFileMatcher.matches(f.toPath))
- log(s"Found ${jars.length} jar dependencies: \n ${jars mkString "\n"}")
- writeExtractedJars(jars, targetPath, out)(log)
+ val jars = classpath.files filter (f => jarFileMatcher.matches(f.toPath))
+ log(s"Found ${jars.length} jar dependencies: \n ${jars mkString "\n"}")
- // TODO: make it in try-catch-finally style
- out.close()
- System.err.println(s"Uber jar created. You can grab it at $jarPath")
- }
- }
-
- /**
- * Writes three attributes to manifest file:
- *
- * Main-Class: classname
- * Manifest-Version: 1.0
- * Created-By: java.runtime.version
- *
- * @param mainClass optional main class
- * @return mainifest for jar
- */
- private def createManifest(mainClass: Option[String]): jar.Manifest = {
- val m = new jar.Manifest()
- m.getMainAttributes.putValue("Manifest-Version", "1.0")
- val createdBy = Option(System.getProperty("java.runtime.version")) getOrElse "1.7.0_06 (Oracle Corporation)"
- m.getMainAttributes.putValue("Created-By", createdBy)
- mainClass foreach { className =>
- m.getMainAttributes.putValue("Main-Class", className)
- }
- m
- }
+ log("Extracting jars...")
+ val extractedJarsRoot = extractJars(jars.distinct)(log).toFile
+ log("Extracting jars - DONE")
- private def writeTarget(compilerTargetDir: File, out: JarOutputStream)(log: String => Unit): Unit = {
- log("Writing target directory...")
- writeFilesToJar(compilerTargetDir.toPath, out)(log)
- log("Writing target directory - DONE")
- }
+ log("Writing jar file...")
+ val optOutput = lib.jarFile(file, Seq(compileTarget, extractedJarsRoot), mainClass)
+ log("Writing jar file - DONE")
- private def writeExtractedJars(jars: Seq[File], targetDir: Path, out: JarOutputStream)(log: String => Unit): Unit = {
- log("Extracting jars")
- val extractedJarsRoot = extractJars(jars)(log)
- log("Extracting jars - DONE")
+ optOutput foreach { uberJar =>
+ System.err.println(s"Uber jar created. You can grab it at $uberJar")
+ }
- log("Writing dependencies...")
- writeFilesToJar(extractedJarsRoot, out)(log)
- log("Writing dependencies - DONE")
}
-
}
diff --git a/plugins/uber-jar/src/uberjar/JarUtils.scala b/plugins/uber-jar/src/uberjar/JarUtils.scala
index f73947e..fa3990c 100644
--- a/plugins/uber-jar/src/uberjar/JarUtils.scala
+++ b/plugins/uber-jar/src/uberjar/JarUtils.scala
@@ -2,64 +2,37 @@ package cbt.uberjar
import java.io.File
import java.nio.file._
-import java.nio.file.attribute.BasicFileAttributes
-import java.util.jar.{JarFile, JarOutputStream}
-import java.util.zip.{ZipEntry, ZipException}
+import java.util.jar.JarFile
private[cbt] trait JarUtils {
- protected val (pathSeparator, jarFileMatcher, excludeFileMatcher) = {
+ protected val (jarFileMatcher, excludeFileMatcher) = {
val fs = FileSystems.getDefault
- (fs.getSeparator, fs.getPathMatcher("glob:**.jar"), fs.getPathMatcher("glob:**{.RSA,.DSA,.SF,.MF}"))
+ (fs.getPathMatcher("glob:**.jar"), fs.getPathMatcher("glob:**{.RSA,.DSA,.SF,.MF,META-INF}"))
}
- /**
- * If `root` is directory: writes content of directory to jar with original mapping
- * If `root` is file: writes this file to jar
- * @param root parent directory, with content should go to jar, or file to be written
- * @param out jar output stream
- * @param log logger
- * @return returns `root`
- */
- protected def writeFilesToJar(root: Path, out: JarOutputStream)(log: String => Unit): Path = {
- Files.walkFileTree(root, new SimpleFileVisitor[Path]() {
- override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = {
- // when we put part of compiled classes, zip already contains some entries. We should not duplicate them.
- try {
- out.putNextEntry(new ZipEntry(root.relativize(file).toString))
- Files.copy(file, out)
- out.closeEntry()
- } catch {
- case e: ZipException => log(s"Failed to add entry, skipping cause: $e")
- }
- FileVisitResult.CONTINUE
- }
-
- override def preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult = {
- // when we put part compiled classes, zip already contains some entries. We should not duplicate them.
- try {
- out.putNextEntry(new ZipEntry(root.relativize(dir).toString + pathSeparator))
- out.closeEntry()
- } catch {
- case e: ZipException => log(s"Failed to add entry, skipping cause: $e")
- }
- FileVisitResult.CONTINUE
- }
- })
+ protected def createJarFile(parent: Path, name: String): File = {
+ val path = parent.resolve(validJarName(name))
+ Files.deleteIfExists(path)
+ Files.createFile(path)
+ path.toFile
}
+ private def validJarName(name: String) = if (name.endsWith(".jar")) name else name + ".jar"
+
/**
* Extracts jars, and writes them on disk. Returns root directory of extracted jars
* TODO: in future we probably should save extracted jars in target directory, to reuse them on second run
+ *
* @param jars list of *.jar files
- * @param log logger
+ * @param log logger
* @return root directory of extracted jars
*/
protected def extractJars(jars: Seq[File])(log: String => Unit): Path = {
val destDir = {
val path = Files.createTempDirectory("unjars")
path.toFile.deleteOnExit()
- log(s"Unjars directory: $path")
+ log(s"Extracted jars directory: $path")
path
}
jars foreach { jar => extractJar(jar, destDir)(log) }
@@ -70,9 +43,10 @@ private[cbt] trait JarUtils {
* Extracts content of single jar file to destination directory.
* When extracting jar, if same file already exists, we skip(don't write) this file.
* TODO: maybe skipping duplicates is not best strategy. Figure out duplicate strategy.
+ *
* @param jarFile jar file to extract
* @param destDir destination directory
- * @param log logger
+ * @param log logger
*/
private def extractJar(jarFile: File, destDir: Path)(log: String => Unit): Unit = {
log(s"Extracting jar: $jarFile")
@@ -85,12 +59,15 @@ private[cbt] trait JarUtils {
if (excludeFileMatcher.matches(entryPath)) {
log(s"Excluded file ${entryPath.getFileName} from jar: $jarFile")
} else {
- if (Files.exists(entryPath)) {
- log(s"File $entryPath already exists, skipping.")
- } else {
- if (entry.isDirectory) {
+ val exists = Files.exists(entryPath)
+ if (entry.isDirectory) {
+ if (!exists) {
Files.createDirectory(entryPath)
// log(s"Created directory: $entryPath")
+ }
+ } else {
+ if (exists) {
+ log(s"File $entryPath already exists, skipping.")
} else {
val is = jar.getInputStream(entry)
Files.copy(is, entryPath)
diff --git a/plugins/uber-jar/src/uberjar/TryWithResources.scala b/plugins/uber-jar/src/uberjar/TryWithResources.scala
deleted file mode 100644
index c2f11f9..0000000
--- a/plugins/uber-jar/src/uberjar/TryWithResources.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-package cbt.uberjar
-
-import java.io.Closeable
-
-import scala.util.Try
-
-private[cbt] object TryWithResources {
- def withCloseable[T <: Closeable, R](t: T)(f: T => R): Try[R] = {
- val result = Try(f(t))
- t.close()
- result
- }
-}
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index 8dd6e72..2e3c0e5 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -214,15 +214,19 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{
} yield file
}
- def jarFile( jarFile: File, files: Seq[File] ): Option[File] = {
+ def jarFile( jarFile: File, files: Seq[File], mainClass: Option[String] = None ): Option[File] = {
if( files.isEmpty ){
None
} else {
jarFile.getParentFile.mkdirs
logger.lib("Start packaging "++jarFile.string)
- val manifest = new Manifest
- manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0")
- val jar = new JarOutputStream(new FileOutputStream(jarFile.toString), manifest)
+ val manifest = new Manifest()
+ manifest.getMainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
+ manifest.getMainAttributes.putValue("Created-By",
+ Option(System.getProperty("java.runtime.version")) getOrElse "1.7.0_06 (Oracle Corporation)")
+ mainClass foreach { className => manifest.getMainAttributes.put(Attributes.Name.MAIN_CLASS, className)
+ }
+ val jar = new JarOutputStream(new FileOutputStream(jarFile), manifest)
try{
val names = for {
base <- files.filter(_.exists).map(realpath)
@@ -235,7 +239,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{
entry.setTime(file.lastModified)
jar.putNextEntry(entry)
jar.write( readAllBytes( file.toPath ) )
- jar.closeEntry
+ jar.closeEntry()
name
}
@@ -245,7 +249,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{
s"Conflicting file names when trying to create $jarFile: "++duplicateFiles.mkString(", ")
)
} finally {
- jar.close
+ jar.close()
}
logger.lib("Done packaging " ++ jarFile.toString)