Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move off of hammerlab-test-utils to break circ-dep #5

Merged
merged 5 commits into from
Jun 20, 2017
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# paths
Scala convenience-wrapper for java.nio.file.Path

[![Build Status](https://travis-ci.org/hammerlab/paths.svg?branch=master)](https://travis-ci.org/hammerlab/paths)
[![Coverage Status](https://coveralls.io/repos/github/hammerlab/paths/badge.svg?branch=master)](https://coveralls.io/github/hammerlab/paths?branch=master)
[![Build Status](https://travis-ci.org/hammerlab/path-utils.svg?branch=master)](https://travis-ci.org/hammerlab/path-utils)
[![Coverage Status](https://coveralls.io/repos/github/hammerlab/path-utils/badge.svg?branch=master)](https://coveralls.io/github/hammerlab/path-utils?branch=master)
[![Maven Central](https://img.shields.io/maven-central/v/org.hammerlab/paths_2.11.svg?maxAge=600)](http://search.maven.org/#search%7Cga%7C1%7Corg.hammerlab%20paths)
8 changes: 6 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
name := "paths"
version := "1.0.2"
deps += libs.value('commons_io)
version := "1.1.0-SNAPSHOT"
deps ++= Seq(
libs.value('commons_io),
libs.value('slf4j)
)
testDeps := Seq(scalatest.value)
addScala212
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("org.hammerlab" % "sbt-parent" % "1.7.3")
addSbtPlugin("org.hammerlab" % "sbt-parent" % "2.0.1")
61 changes: 61 additions & 0 deletions src/main/scala/org/hammerlab/paths/FileSystems.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.hammerlab.paths

import java.lang.reflect.Field
import java.nio.file.spi.FileSystemProvider

import grizzled.slf4j.Logging

import scala.collection.JavaConverters._

object FileSystems
extends Logging {

private var _filesystemsInitialized = false
def init(): Unit = {

this.synchronized {
if (!_filesystemsInitialized) {
val cls = classOf[FileSystemProvider]

def getField(name: String): Field = {
val field = cls.getDeclaredField(name)
field.setAccessible(true)
field
}

val lockField = getField("lock")
val lock = lockField.get(null)

val loadingProvidersField = getField("loadingProviders")
val installedProvidersField = getField("installedProviders")

lock.synchronized {
if (loadingProvidersField.get(null).asInstanceOf[Boolean]) {
logger.info("FileSystems already loaded! forcing reload")
loadingProvidersField.set(null, false)
installedProvidersField.set(null, null)
} else {
logger.info("Loading filesystems")
}
load()
_filesystemsInitialized = true

}
}
}
}

private def load(): Unit = {
/** Hack to pick up [[FileSystemProvider]] implementations; see https://issues.scala-lang.org/browse/SI-10247. */
val scl = classOf[ClassLoader].getDeclaredField("scl")
scl.setAccessible(true)
val prevClassLoader = ClassLoader.getSystemClassLoader
scl.set(null, Thread.currentThread().getContextClassLoader)

logger.info(
s"Loaded filesystems for schemes: ${FileSystemProvider.installedProviders().asScala.map(_.getScheme).mkString(",")}"
)

scl.set(null, prevClassLoader)
}
}
38 changes: 29 additions & 9 deletions src/main/scala/org/hammerlab/paths/Path.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.hammerlab.paths

import java.io.{ InputStream, OutputStream, PrintWriter }
import java.io.{ InputStream, ObjectStreamException, OutputStream, PrintWriter }
import java.net.URI
import java.nio.file.Files.{ newDirectoryStream, newInputStream, newOutputStream, readAllBytes }
import java.nio.file.{ DirectoryStream, Files, Paths, Path ⇒ JPath }
Expand All @@ -9,11 +9,20 @@ import org.apache.commons.io.FilenameUtils.getExtension

import scala.collection.JavaConverters._

class Path(val path: JPath)
extends AnyVal
with Serializable {
case class Path(path: JPath) {

override def toString: String = path.toString
@throws[ObjectStreamException]
def writeReplace: Object = {
val sp = new SerializablePath
sp.str = toString
sp
}

override def toString: String =
if (path.isAbsolute)
uri.toString
else
path.toString

def uri: URI = path.toUri

Expand Down Expand Up @@ -80,7 +89,7 @@ class Path(val path: JPath)
/**
* Append `suffix` to the basename of this [[Path]].
*/
def +(suffix: String): Path = Path(path.toString + suffix)
def +(suffix: String): Path = Path(toString + suffix)

def /(basename: String): Path = Path(path.resolve(basename))

Expand All @@ -107,17 +116,28 @@ class Path(val path: JPath)
}

object Path {
def apply(path: JPath): Path = new Path(path)

import FileSystems.init

private def get(pathStr: String): JPath = {
init()
Paths.get(pathStr)
}

private def get(uri: URI): JPath = {
init()
Paths.get(uri)
}

def apply(pathStr: String): Path = {
val uri = new URI(pathStr)
if (uri.getScheme == null)
new Path(Paths.get(pathStr))
new Path(get(pathStr))
else
Path(uri)
}

def apply(uri: URI): Path = new Path(Paths.get(uri))
def apply(uri: URI): Path = Path(get(uri))

implicit def toJava(path: Path): JPath = path.path
}
10 changes: 10 additions & 0 deletions src/main/scala/org/hammerlab/paths/SerializablePath.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.hammerlab.paths

class SerializablePath
extends Serializable {

// Relative paths put their toString here, others put their uri.toString
var str: String = _

def readResolve: Any = Path(str)
}
53 changes: 47 additions & 6 deletions src/test/scala/org/hammerlab/paths/PathTest.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package org.hammerlab.paths

import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream }
import java.nio.file.Files
import java.nio.file.Files.createDirectory
import java.nio.file.Files.{ createDirectory, createTempDirectory }

import org.hammerlab.test.Suite
import org.hammerlab.test.matchers.seqs.SeqMatcher.seqMatch
import org.scalatest.{ BeforeAndAfterAll, FunSuite, Matchers }

import scala.collection.mutable.ArrayBuffer

class PathTest
extends Suite {
extends FunSuite
with Matchers
with BeforeAndAfterAll {

implicit def strToPath(str: String): Path = Path(str)

test("extensions") {
Expand Down Expand Up @@ -58,14 +63,14 @@ class PathTest

assert(baz.exists)

dir.list.toSeq should seqMatch(
dir.list.toSeq should be(
Seq(
bar,
foo
)
)

dir.walk.toSeq should seqMatch(
dir.walk.toSeq should be(
Seq(
dir,
bar,
Expand Down Expand Up @@ -100,4 +105,40 @@ class PathTest
path.writeLines(lines)
path.lines.toSeq should be(lines)
}

test("serialize path") {
val path = Path("abc/def")
val baos = new ByteArrayOutputStream()
val oos = new ObjectOutputStream(baos)

oos.writeObject(path)

val bytes = baos.toByteArray
bytes.length should be(94)

val bais = new ByteArrayInputStream(bytes)
val ois = new ObjectInputStream(bais)

ois.readObject().asInstanceOf[Path] should be(path)
}

val dirs = ArrayBuffer[Path]()

def tmpDir(prefix: String = this.getClass.getSimpleName): Path = {
val f = Path(createTempDirectory(prefix))
dirs += f
f
}

/**
* Return a [[Path]] to a temporary file that has not yet been created.
*/
def tmpPath(prefix: String = this.getClass.getSimpleName,
suffix: String = ""): Path =
tmpDir() / (prefix + suffix)

override def afterAll(): Unit = {
super.afterAll()
dirs.foreach(d ⇒ if (d.exists) d.delete(true))
}
}