commit cbdb8902b05da72e08fe4e28512b67660693b5bc Author: Julian Ospald Date: Wed Jan 29 16:38:35 2020 +0100 Initial commit diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dbaef03 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for streamly-files + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7ecfe24 --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2020, Julian Ospald + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Julian Ospald nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/cabal.project b/cabal.project new file mode 100644 index 0000000..6f31784 --- /dev/null +++ b/cabal.project @@ -0,0 +1,6 @@ +packages: ./streamly-filesystem.cabal + +source-repository-package + type: git + location: https://github.com/composewell/streamly.git + tag: 753d091b75bd0d493b130a7eb66b283a949994e3 diff --git a/src/Streamly/External/FileSystem/Handle/Posix.hs b/src/Streamly/External/FileSystem/Handle/Posix.hs new file mode 100644 index 0000000..7f38bf1 --- /dev/null +++ b/src/Streamly/External/FileSystem/Handle/Posix.hs @@ -0,0 +1,116 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiWayIf #-} + +-- | +-- Module : Streamly.External.FileSystem.Handle.Posix +-- Copyright : © 2020 Julian Ospald +-- License : BSD3 +-- +-- Maintainer : Julian Ospald +-- Stability : experimental +-- Portability : portable +-- +-- This module provides high-level file streaming API. +module Streamly.External.FileSystem.Handle.Posix where + +import Streamly +import Streamly.Memory.Array +import qualified Streamly.Memory.Array as A +import qualified Streamly.FileSystem.Handle as FH +import qualified Streamly.Internal.FileSystem.Handle + as IFH +import qualified Streamly.Prelude as S +import qualified Streamly.Internal.Prelude as S +import System.IO ( Handle + , hClose + ) +import Control.Monad.IO.Class ( liftIO + , MonadIO + ) +import Data.Word ( Word8 ) +import Data.Word8 +import Control.Exception.Safe +import qualified Data.ByteString.Lazy as L +import qualified Data.ByteString as BS +import qualified Streamly.External.ByteString as Strict +import qualified Data.ByteString.Lazy.Internal as BSLI +import System.IO.Unsafe +import qualified Streamly.Internal.Data.Unfold as SIU +import Streamly.Internal.Data.Unfold.Types +import System.Posix.RawFilePath.Directory.Traversals +import qualified Streamly.Internal.Data.Stream.StreamD.Type + as D +import System.Posix.ByteString +import System.Posix.Foreign ( DirType ) +import System.Posix.Directory.ByteString + as PosixBS + + +-- |Read the given file lazily as a lazy ByteString. +-- +-- The handle is closed automatically, when the stream exits normally, +-- aborts or gets garbage collected. +-- +-- This uses `unsafeInterleaveIO` under the hood. +readFile :: Handle -> IO L.ByteString +readFile handle' = fromChunks (readFileStream handle') + where + -- https://github.com/psibi/streamly-bytestring/issues/7 + fromChunks = + S.foldrM (\x b -> unsafeInterleaveIO b >>= pure . BSLI.chunk x) + (pure BSLI.Empty) + . S.map Strict.fromArray + + +-- | Read from the given handle as a streamly filestream. +-- +-- The handle is closed automatically, when the stream exits normally, +-- aborts or gets garbage collected. +readFileStream :: (MonadCatch m, MonadAsync m) + => Handle + -> SerialT m (Array Word8) +readFileStream = S.unfold + (SIU.finallyIO (liftIO . hClose) + FH.readChunks + ) + + +-- | Like 'copyFileStream', except for two file handles. +copyFile :: (MonadCatch m, MonadAsync m, MonadMask m) + => Handle + -> Handle + -> m () +copyFile fromHandle toHandle = + copyFileStream (readFileStream fromHandle) toHandle + + +-- | Copy a stream to a file handle. +-- +-- The handle is closed automatically after the stream is copied. +copyFileStream :: (MonadCatch m, MonadAsync m, MonadMask m) + => SerialT m (Array Word8) -- ^ stream to copy + -> Handle -- ^ file handle to copy to + -> m () +copyFileStream stream handle' = + finally (liftIO $ hClose handle') $ S.fold (FH.writeChunks handle') stream + + +unfoldDirectoryContents :: MonadIO m + => Unfold m DirStream (DirType, RawFilePath) +unfoldDirectoryContents = Unfold step return + where + {-# INLINE [0] step #-} + step dirstream = do + (typ, e) <- liftIO $ readDirEnt dirstream + return if + | BS.null e -> D.Stop + | BS.pack [_period] == e -> D.Skip dirstream + | BS.pack [_period, _period] == e -> D.Skip dirstream + | otherwise -> D.Yield (typ, e) dirstream + + +getDirectoryContents :: (MonadCatch m, MonadAsync m, MonadMask m) + => DirStream + -> SerialT m (DirType, RawFilePath) +getDirectoryContents = S.unfold + (SIU.finallyIO (liftIO . PosixBS.closeDirStream) unfoldDirectoryContents) diff --git a/streamly-filesystem.cabal b/streamly-filesystem.cabal new file mode 100644 index 0000000..51e1b06 --- /dev/null +++ b/streamly-filesystem.cabal @@ -0,0 +1,38 @@ +cabal-version: >=1.10 + +name: streamly-filesytem +version: 0.1.0.0 +synopsis: Beautiful file streaming +-- description: +bug-reports: https://github.com/hasufell/streamly-filesystem/issues +license: BSD3 +license-file: LICENSE +author: Julian Ospald +maintainer: Julian Ospald +copyright: Julian Ospald 2020 +category: Streaming +build-type: Simple +extra-source-files: CHANGELOG.md + +library + if os(windows) -- not supported yet + build-depends: unbuildable<0 + buildable: False + exposed-modules: Streamly.External.FileSystem.Handle.Posix + -- other-modules: + -- other-extensions: + build-depends: base >= 4.12 && < 5 + , bytestring >= 0.10 + , hpath-directory >= 0.13 + , safe-exceptions >= 0.1 + , streamly >= 0.7 + , streamly-bytestring >= 0.1.0.1 + , unix >= 2.7 + , word8 >= 0.1.3 + hs-source-dirs: src + default-language: Haskell2010 + GHC-Options: -Wall -O2 -fspec-constr-recursive=16 -fmax-worker-args=16 + +source-repository head + type: git + location: https://github.com/hasufell/streamly-filesystem