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

Add root to Path & root constructor #196

Merged
merged 13 commits into from
Oct 18, 2023
9 changes: 9 additions & 0 deletions os/src-jvm/package.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import scala.language.implicitConversions
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Paths

package object os {
type Generator[+T] = geny.Generator[T]
Expand All @@ -10,6 +13,12 @@ package object os {
*/
val root: Path = Path(java.nio.file.Paths.get(".").toAbsolutePath.getRoot)

def root(root: String, fileSystem: FileSystem = FileSystems.getDefault()): Path = {
val path = Path(fileSystem.getPath(root))
assert(path.root == root, s"$root is not a root path")
path
}

def resource(implicit resRoot: ResourceRoot = Thread.currentThread().getContextClassLoader) = {
os.ResourcePath.resource(resRoot)
}
Expand Down
8 changes: 8 additions & 0 deletions os/src-native/package.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import java.nio.file.FileSystem
import java.nio.file.FileSystems
package object os {
type Generator[+T] = geny.Generator[T]
val Generator = geny.Generator
Expand All @@ -8,6 +10,12 @@ package object os {
*/
val root: Path = Path(java.nio.file.Paths.get(".").toAbsolutePath.getRoot)

def root(root: String, fileSystem: FileSystem = FileSystems.getDefault()): Path = {
val path = Path(fileSystem.getPath(root))
assert(path.root == root, s"$root is not a root path")
path
}

/**
* The user's home directory
*/
Expand Down
3 changes: 3 additions & 0 deletions os/src/Path.scala
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,9 @@ class Path private[os] (val wrapped: java.nio.file.Path)
new SeekableSource.ChannelSource(java.nio.file.Files.newByteChannel(wrapped))

require(wrapped.isAbsolute || Path.driveRelative(wrapped), s"$wrapped is not an absolute path")
def root = Option(wrapped.getRoot).map(_.toString).getOrElse("")
lihaoyi marked this conversation as resolved.
Show resolved Hide resolved
def fileSystem = wrapped.getFileSystem()

def segments: Iterator[String] = wrapped.iterator().asScala.map(_.toString)
def getSegment(i: Int): String = wrapped.getName(i).toString
def segmentCount = wrapped.getNameCount
Expand Down
16 changes: 16 additions & 0 deletions os/test/src-jvm/PathTestsJvmOnly.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import java.nio.file.Paths

import os._
import utest._
import java.util.HashMap
import java.nio.file.FileSystems
import java.net.URI

object PathTestsJvmOnly extends TestSuite {
val tests = Tests {
test("construction") {
Expand Down Expand Up @@ -40,6 +44,18 @@ object PathTestsJvmOnly extends TestSuite {
names.foreach(p => assert(!exists(twd / p)))
}
}
test("custom filesystem") { // native doesnt support custom fs yet
val path: java.nio.file.Path = java.nio.file.Paths.get("foo.jar");
val uri = new URI("jar", path.toUri().toString(), null);

val env = new HashMap[String, String]();
env.put("create", "true");

val fileSystem = FileSystems.newFileSystem(uri, env);
val p = os.root("/", fileSystem) / "test" / "dir"
assert(p.root == "/")
assert(p.fileSystem == fileSystem)
Copy link
Member

@lihaoyi lihaoyi Oct 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a few more operations here? e.g.

  1. Running more operations we expect should work on foo.jar: os.read, os.read.*, os.write, os.write.*, os.list, os.walk, os.remove, os.remove.all, os.copy, os.move, os.makeDir

  2. Some negative examples of running operations that we should expect to fail when run on an os.Path inside foo.jar: os.symlink, os.temp with an explicit dir: os.Path, os.stat, os.perms, os.proc() passing the os.Path inside foo.jar both as a os.Shellable and cwd/stdin/stdout/stderr. Assert on the exception type so we know what we're getting back on failure; the underlying java.nio exception is fine for the cases where things already fail when they should, though some things like os.proc we may have to check and throw our own exception

  3. Further manipulation of the paths with a custom filesystem via os.up, / os.RelPath, / os.SubPath, and ensuring the root ends up in the same place

  4. Checking that os.Paths with the same segments but different roots or different filesystem do not return == to each other

  5. os.relativeTo and os.subRelativeTo between paths on different filesystems should probably throw an exception, so let's assert that. Should they also throw exceptions when run between paths on different roots on the same filesystem?

This is enough stuff that it's probably worth moving the test suite into a separate file

}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions os/test/src/PathTests.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package test.os

import java.nio.file.Paths
import java.io.File

import os._
import os.Path.{driveRoot}
Expand Down Expand Up @@ -420,6 +421,14 @@ object PathTests extends TestSuite {
assert(result1 == expected)
assert(result2 == expected)
}
test("custom root") {
assert(os.root == os.root(os.root.root))
File.listRoots().foreach { root =>
val path = os.root(root.toPath().toString) / "test" / "dir"
assert(path.root == root.toString)
assert(path.relativeTo(os.root(root.toPath().toString)) == rel / "test" / "dir")
}
}
test("issue201") {
val p = Path("/omg") // driveRelative path does not throw exception.
System.err.printf("p[%s]\n", posix(p))
Expand Down
Loading