All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pantsbuild.zinc.compiler.OutputUtils.scala Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2012 Typesafe, Inc. 
 */

package org.pantsbuild.zinc.compiler

import java.io.File
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.{FileVisitResult, Files, Path, Paths, SimpleFileVisitor}
import java.util.jar.{JarEntry, JarInputStream, JarOutputStream}
import scala.annotation.tailrec
import scala.collection.mutable

object OutputUtils {

  /**
   * Sort the contents of the `dir` in lexicographic order.
   *
   * @param dir File handle containing the contents to sort
   * @return sorted set of all paths within the `dir`
   */
  def sort(dir:File): mutable.TreeSet[Path] = {
    val sorted = new mutable.TreeSet[Path]()

    val fileSortVisitor = new SimpleFileVisitor[Path]() {
      override def preVisitDirectory(path: Path, attrs: BasicFileAttributes): FileVisitResult = {
        if (!path.endsWith("/")) {
          sorted.add(Paths.get(path.toString, "/"))
        } else {
          sorted.add(path)
        }
        FileVisitResult.CONTINUE
      }

      override def visitFile(path: Path, attrs: BasicFileAttributes): FileVisitResult = {
        sorted.add(path)
        FileVisitResult.CONTINUE
      }
    }

    Files.walkFileTree(dir.toPath, fileSortVisitor)
    sorted
  }

  def relativize(base: String, path: Path): String = {
    new File(base.toString).toURI().relativize(new File(path.toString).toURI()).getPath()
  }

  /**
   * Create a JAR of of filePaths provided.
   *
   * @param filePaths set of all paths to be added to the JAR
   * @param outputJarPath Absolute Path to the output JAR being created
   * @param jarEntryTime time to be set for each JAR entry
   */
  def createJar(
    base: String, filePaths: mutable.TreeSet[Path], outputJarPath: Path, jarEntryTime: Long) {

    val target = new JarOutputStream(Files.newOutputStream(outputJarPath))

    def jarEntry(name: String): JarEntry = {
      val jarEntry = new JarEntry(name)
      // setting jarEntry time to a fixed value for all entries within the jar so that jars are
      // byte-for-byte reproducible.
      jarEntry.setTime(jarEntryTime)
      jarEntry
    }

    def addToJar(source: Path, entryName: String): FileVisitResult = {
      if (source.toFile.isDirectory) {
        target.putNextEntry(jarEntry(entryName))
      } else {
        target.putNextEntry(jarEntry(entryName))
        Files.copy(source, target)
      }
      target.closeEntry()
      FileVisitResult.CONTINUE
    }

    val pathToName = filePaths.zipWithIndex.map{case(k, v) => (k, relativize(base, k))}.toMap
    pathToName.map(e => addToJar(e._1, e._2))
    target.close()
  }

  /**
   * Jar the contents of output classes (settings.classesDirectory) and copy to settings.outputJar
   *
   */
  def createClassesJar(classesDirectory: File, outputJarPath: Path, jarCreationTime: Long) = {

    // Sort the contents of the classesDirectory for deterministic jar creation
    val sortedClasses = sort(classesDirectory)

    createJar(classesDirectory.toString, sortedClasses, outputJarPath, jarCreationTime)
  }

  /**
   * Determines if a file exists in a JAR provided.
   *
   * @param jarPath Absolute Path to the JAR being inspected
   * @param fileName Name of the file, the existence of which is to be inspected
   * @return
   */
  def existsClass(jarPath: Path, fileName: String): Boolean = {
    var jis: JarInputStream = null
    var found = false
    try {
      jis = new JarInputStream(Files.newInputStream(jarPath))

      @tailrec
      def findClass(entry: JarEntry): Boolean = entry match {
        case null =>
          false
        case entry if entry.getName == fileName =>
          true
        case _ =>
          findClass(jis.getNextJarEntry)
      }

      found = findClass(jis.getNextJarEntry)
    } finally {
      jis.close()
    }
    found
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy