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

scala.scalanative.io.VirtualDirectory.scala Maven / Gradle / Ivy

The newest version!
package scala.scalanative
package io

import scala.collection.mutable
import scala.collection.JavaConverters._
import java.io.File
import java.net.URI
import java.nio.ByteBuffer
import java.nio.file._
import java.nio.channels._
import scalanative.util.{acquire, defer, Scope}

sealed trait VirtualDirectory {

  /** Check if file with given path is in the directory. */
  def contains(path: Path): Boolean =
    files.contains(path)

  /** Reads a contents of file with given path. */
  def read(path: Path): ByteBuffer

  /** Replaces contents of file with given value. */
  def write(path: Path, buffer: ByteBuffer): Unit

  /** List all files in this directory. */
  def files: Seq[Path]
}

object VirtualDirectory {

  /** Real, non-virtual directory on local file system. */
  def local(file: File): VirtualDirectory = {
    def absolute = file.getAbsolutePath
    assert(file.exists, s"Local directory doesn't exist: $absolute")
    assert(file.isDirectory, s"Not a directory: $absolute")

    new LocalDirectory(file.toPath)
  }

  /** Virtual directory that represents contents of the jar file. */
  def jar(file: File)(implicit in: Scope): VirtualDirectory = {
    val absolute = file.getAbsolutePath
    assert(file.exists, s"Jar doesn't exist: $absolute")
    assert(absolute.endsWith(".jar"), s"Not a jar: $absolute")

    new JarDirectory(file.toPath)
  }

  /** Virtual directory based on either local directory or a jar. */
  def real(file: File)(implicit in: Scope): VirtualDirectory =
    if (file.isDirectory) {
      local(file)
    } else if (file.getAbsolutePath.endsWith(".jar")) {
      jar(file)
    } else {
      throw new UnsupportedOperationException(
        "Neither a jar, nor a directory: " + file)
    }

  /** Empty directory that contains no files. */
  val empty: VirtualDirectory = EmptyDirectory

  private trait NioDirectory extends VirtualDirectory {
    protected def resolve(path: Path): Path = path

    protected def open(path: Path) =
      FileChannel.open(path,
                       StandardOpenOption.CREATE,
                       StandardOpenOption.WRITE,
                       StandardOpenOption.TRUNCATE_EXISTING)

    override def read(path: Path): ByteBuffer = {
      val bytes  = Files.readAllBytes(resolve(path))
      val buffer = ByteBuffer.wrap(bytes)
      buffer
    }

    override def write(path: Path, buffer: ByteBuffer): Unit = {
      val channel = open(resolve(path))
      try channel.write(buffer)
      finally channel.close
    }
  }

  private final class LocalDirectory(path: Path) extends NioDirectory {
    override protected def resolve(path: Path): Path =
      this.path.resolve(path)

    override def files: Seq[Path] =
      Files
        .walk(path, Integer.MAX_VALUE, FileVisitOption.FOLLOW_LINKS)
        .iterator()
        .asScala
        .map(fp => path.relativize(fp))
        .toSeq
  }

  private final class JarDirectory(path: Path)(implicit in: Scope)
      extends NioDirectory {
    private val fileSystem: FileSystem =
      acquire(
        FileSystems.newFileSystem(URI.create(s"jar:${path.toUri}"),
                                  Map("create" -> "false").asJava))

    override def files: Seq[Path] = {
      val roots = fileSystem.getRootDirectories.asScala.toSeq

      roots
        .flatMap { path =>
          Files
            .walk(path, Integer.MAX_VALUE, FileVisitOption.FOLLOW_LINKS)
            .iterator()
            .asScala
        }
    }
  }

  private final object EmptyDirectory extends VirtualDirectory {
    override def files = Seq.empty

    override def read(path: Path): ByteBuffer =
      throw new UnsupportedOperationException(
        "Can't read from empty directory.")

    override def write(path: Path, buffer: ByteBuffer): Unit =
      throw new UnsupportedOperationException(
        "Can't write to empty directory.")
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy