From 842f199777393c64ea0ce61cbf1caf651a5576da Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 8 Oct 2024 09:23:59 +0200 Subject: [PATCH 1/2] . --- os/src/Path.scala | 6 ++++-- os/src/Source.scala | 5 +++++ os/test/src/SourceTests.scala | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 os/test/src/SourceTests.scala diff --git a/os/src/Path.scala b/os/src/Path.scala index 35631cb3..37639686 100644 --- a/os/src/Path.scala +++ b/os/src/Path.scala @@ -534,8 +534,10 @@ trait ReadablePath { */ class Path private[os] (val wrapped: java.nio.file.Path) extends FilePath with ReadablePath with BasePathImpl { - def toSource: SeekableSource = - new SeekableSource.ChannelSource(java.nio.file.Files.newByteChannel(wrapped)) + def toSource: SeekableSource = new SeekableSource.ChannelLengthSource( + java.nio.file.Files.newByteChannel(wrapped), + java.nio.file.Files.size(wrapped) + ) require(wrapped.isAbsolute || Path.driveRelative(wrapped), s"$wrapped is not an absolute path") def root = Option(wrapped.getRoot).map(_.toString).getOrElse("") diff --git a/os/src/Source.scala b/os/src/Source.scala index 002dca09..c0231e55 100644 --- a/os/src/Source.scala +++ b/os/src/Source.scala @@ -115,4 +115,9 @@ object SeekableSource { implicit class ChannelSource(cn: SeekableByteChannel) extends SeekableSource { def getHandle() = Right(cn) } + class ChannelLengthSource(cn: SeekableByteChannel, length: Long) extends SeekableSource { + def getHandle() = Right(cn) + + override def contentLength: Option[Long] = Some(length) + } } diff --git a/os/test/src/SourceTests.scala b/os/test/src/SourceTests.scala new file mode 100644 index 00000000..f7791d26 --- /dev/null +++ b/os/test/src/SourceTests.scala @@ -0,0 +1,16 @@ +package test.os +import utest.{assert => _, _} + +object SourceTests extends TestSuite { + + val tests = Tests { + test("contentMetadata") - TestUtil.prep { wd => + // content type for all files is just treated as application/octet-stream, + // we do not do any clever mime-type inference or guessing + (wd / "folder1/one.txt").toSource.httpContentType ==> Some("application/octet-stream") + // length is taken from the filesystem at the moment at which `.toSource` is called + (wd / "folder1/one.txt").toSource.contentLength ==> Some(22) + (wd / "File.txt").toSource.contentLength ==> Some(8) + } + } +} From 29834835bde34d5403c1a698a8ea895be92bc54f Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 8 Oct 2024 09:29:43 +0200 Subject: [PATCH 2/2] . --- os/src/ReadWriteOps.scala | 1 + os/src/Source.scala | 2 ++ os/test/src/SourceTests.scala | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/os/src/ReadWriteOps.scala b/os/src/ReadWriteOps.scala index ee70a157..3ea0d83d 100644 --- a/os/src/ReadWriteOps.scala +++ b/os/src/ReadWriteOps.scala @@ -247,6 +247,7 @@ object read extends Function1[ReadablePath, String] { object stream extends Function1[ReadablePath, geny.Readable] { def apply(p: ReadablePath): geny.Readable = new geny.Readable { + override def contentLength: Option[Long] = p.toSource.contentLength def readBytesThrough[T](f: java.io.InputStream => T): T = { val is = p.getInputStream try f(is) diff --git a/os/src/Source.scala b/os/src/Source.scala index c0231e55..75c291a8 100644 --- a/os/src/Source.scala +++ b/os/src/Source.scala @@ -66,6 +66,8 @@ object Source extends WritableLowPri { implicit class WritableSource[T](s: T)(implicit f: T => geny.Writable) extends Source { val writable = f(s) + + override def contentLength: Option[Long] = writable.contentLength def getHandle() = Left(writable) } } diff --git a/os/test/src/SourceTests.scala b/os/test/src/SourceTests.scala index f7791d26..54a0a4f4 100644 --- a/os/test/src/SourceTests.scala +++ b/os/test/src/SourceTests.scala @@ -11,6 +11,11 @@ object SourceTests extends TestSuite { // length is taken from the filesystem at the moment at which `.toSource` is called (wd / "folder1/one.txt").toSource.contentLength ==> Some(22) (wd / "File.txt").toSource.contentLength ==> Some(8) + + // Make sure the `Writable` returned by `os.read.stream` propagates the content length + os.read.stream(wd / "folder1/one.txt").contentLength ==> Some(22) + // Even when converted to an `os.Source` + (os.read.stream(wd / "folder1/one.txt"): os.Source).contentLength ==> Some(22) } } }