packages feed

zip-stream 0.1.0.1 → 0.1.1

raw patch · 7 files changed

+86/−31 lines, 7 filesdep ~basedep ~conduitdep ~conduit-extraPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, conduit, conduit-extra

API changes (from Hackage documentation)

+ Codec.Archive.Zip.Conduit.Types: instance GHC.Base.Monad m => Data.Semigroup.Semigroup (Codec.Archive.Zip.Conduit.Types.ZipData m)
- Codec.Archive.Zip.Conduit.Types: ZipDataSource :: (Source m ByteString) -> ZipData m
+ Codec.Archive.Zip.Conduit.Types: ZipDataSource :: (ConduitM () ByteString m ()) -> ZipData m
- Codec.Archive.Zip.Conduit.Types: sourceZipData :: Monad m => ZipData m -> Source m ByteString
+ Codec.Archive.Zip.Conduit.Types: sourceZipData :: Monad m => ZipData m -> ConduitM () ByteString m ()
- Codec.Archive.Zip.Conduit.UnZip: unZipStream :: (MonadBase b m, PrimMonad b, MonadThrow m) => ConduitM ByteString (Either ZipEntry ByteString) m ZipInfo
+ Codec.Archive.Zip.Conduit.UnZip: unZipStream :: (MonadThrow m, PrimMonad m) => ConduitM ByteString (Either ZipEntry ByteString) m ZipInfo
- Codec.Archive.Zip.Conduit.Zip: ZipDataSource :: (Source m ByteString) -> ZipData m
+ Codec.Archive.Zip.Conduit.Zip: ZipDataSource :: (ConduitM () ByteString m ()) -> ZipData m
- Codec.Archive.Zip.Conduit.Zip: zipStream :: (MonadBase b m, PrimMonad b, MonadThrow m) => ZipOptions -> ConduitM (ZipEntry, ZipData m) ByteString m Word64
+ Codec.Archive.Zip.Conduit.Zip: zipStream :: (MonadThrow m, PrimMonad m) => ZipOptions -> ConduitM (ZipEntry, ZipData m) ByteString m Word64

Files

Codec/Archive/Zip/Conduit/Internal.hs view
@@ -1,5 +1,6 @@+{-# LANGUAGE CPP #-} module Codec.Archive.Zip.Conduit.Internal-  ( zipVersion+  ( osVersion, zipVersion   , zipError   , idConduit   , sizeCRC@@ -15,18 +16,29 @@ import qualified Data.Conduit as C import qualified Data.Conduit.Internal as CI import           Data.Digest.CRC32 (crc32Update)-import           Data.Word (Word16, Word32, Word64)+import           Data.Word (Word8, Word32, Word64)  import           Codec.Archive.Zip.Conduit.Types --- |The version of this zip program, really just rough indicator of compatibility-zipVersion :: Word16+#if MIN_VERSION_conduit(1,3,0)+#define ConduitM ConduitT+#define PRE13(x)+#else+#define PRE13(x) x+#endif++-- | The version of this zip program, really just rough indicator of compatibility+zipVersion :: Word8 zipVersion = 48 +-- | The OS this implementation tries to be compatible to+osVersion :: Word8+osVersion = 0 -- DOS+ zipError :: MonadThrow m => String -> m a zipError = throwM . ZipError -idConduit :: Monad m => C.Conduit a m a+idConduit :: Monad m => C.ConduitM a a m () idConduit = C.awaitForever C.yield  passthroughFold :: Monad m => (a -> b -> a) -> a -> C.ConduitM b b m a@@ -42,16 +54,16 @@ sizeC :: Monad m => C.ConduitM BS.ByteString BS.ByteString m Word64 sizeC = passthroughFold (\l b -> l + fromIntegral (BS.length b)) 0 -- fst <$> sizeCRC -outputSize :: Monad m => C.Conduit i m BS.ByteString -> C.ConduitM i BS.ByteString m Word64+outputSize :: Monad m => C.ConduitM i BS.ByteString m () -> C.ConduitM i BS.ByteString m Word64 outputSize = (C..| sizeC) -inputSize :: Monad m => C.Conduit BS.ByteString m o -> C.ConduitM BS.ByteString o m Word64+inputSize :: Monad m => C.ConduitM BS.ByteString o m () -> C.ConduitM BS.ByteString o m Word64 -- inputSize = fuseUpstream sizeC -- won't work because we need to deal with leftovers properly inputSize (CI.ConduitM src) = CI.ConduitM $ \rest -> let   go n (CI.Done ()) = rest n   go n (CI.PipeM m) = CI.PipeM $ go n <$> m   go n (CI.Leftover p b) = CI.Leftover (go (n - fromIntegral (BS.length b)) p) b-  go n (CI.HaveOutput p f o) = CI.HaveOutput (go n p) f o+  go n (CI.HaveOutput p PRE13(f) o) = CI.HaveOutput (go n p) PRE13(f) o   go n (CI.NeedInput p q) = CI.NeedInput (\b -> go (n + fromIntegral (BS.length b)) (p b)) (go n . q)   in go 0 (src CI.Done) 
Codec/Archive/Zip/Conduit/Types.hs view
@@ -5,6 +5,7 @@ import qualified Data.ByteString.Lazy as BSL import qualified Data.Conduit as C import           Data.Conduit.Binary (sourceLbs)+import           Data.Semigroup (Semigroup(..)) import           Data.String (IsString(..)) import           Data.Time.LocalTime (LocalTime) import           Data.Typeable (Typeable)@@ -36,15 +37,18 @@ -- |The data contents for a 'ZipEntry'. For empty entries (e.g., directories), use 'mempty'. data ZipData m   = ZipDataByteString BSL.ByteString -- ^A known ByteString, which will be fully evaluated (not streamed)-  | ZipDataSource (C.Source m ByteString) -- ^A byte stream producer, streamed (and compressed) directly into the zip+  | ZipDataSource (C.ConduitM () ByteString m ()) -- ^A byte stream producer, streamed (and compressed) directly into the zip +instance Monad m => Semigroup (ZipData m) where+  ZipDataByteString a <> ZipDataByteString b = ZipDataByteString $ mappend a b+  a <> b = ZipDataSource $ mappend (sourceZipData a) (sourceZipData b)+ instance Monad m => Monoid (ZipData m) where   mempty = ZipDataByteString BSL.empty-  mappend (ZipDataByteString a) (ZipDataByteString b) = ZipDataByteString $ mappend a b-  mappend a b = ZipDataSource $ mappend (sourceZipData a) (sourceZipData b)+  mappend = (<>)  -- |Normalize any 'ZipData' to a simple source-sourceZipData :: Monad m => ZipData m -> C.Source m ByteString+sourceZipData :: Monad m => ZipData m -> C.ConduitM () ByteString m () sourceZipData (ZipDataByteString b) = sourceLbs b sourceZipData (ZipDataSource s) = s 
Codec/Archive/Zip/Conduit/UnZip.hs view
@@ -1,4 +1,5 @@ -- |Stream the extraction of a zip file, e.g., as it's being downloaded.+{-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RankNTypes #-} module Codec.Archive.Zip.Conduit.UnZip@@ -9,7 +10,9 @@  import           Control.Applicative ((<|>), empty) import           Control.Monad (when, unless, guard)+#if !MIN_VERSION_conduit(1,3,0) import           Control.Monad.Base (MonadBase)+#endif import           Control.Monad.Catch (MonadThrow) import           Control.Monad.Primitive (PrimMonad) import qualified Data.Binary.Get as G@@ -28,7 +31,7 @@  data Header m   = FileHeader-    { fileDecompress :: C.Conduit BS.ByteString m BS.ByteString+    { fileDecompress :: C.ConduitM BS.ByteString BS.ByteString m ()     , fileEntry :: !ZipEntry     , fileCRC :: !Word32     , fileCSize :: !Word64@@ -53,7 +56,7 @@   } -} -pass :: (MonadThrow m, Integral n) => n -> C.Conduit BS.ByteString m BS.ByteString+pass :: (MonadThrow m, Integral n) => n -> C.ConduitM BS.ByteString BS.ByteString m () pass 0 = return () pass n = C.await >>= maybe   (zipError $ "EOF in file data, expecting " ++ show ni ++ " more bytes")@@ -94,7 +97,14 @@ -- It does not (ironically) support uncompressed zip files that have been created as streams, where file sizes are not known beforehand. -- Since it does not use the offset information at the end of the file, it assumes all entries are packed sequentially, which is usually the case. -- Any errors are thrown in the underlying monad (as 'ZipError's or 'Data.Conduit.Serialization.Binary.ParseError').-unZipStream :: (MonadBase b m, PrimMonad b, MonadThrow m) => C.ConduitM BS.ByteString (Either ZipEntry BS.ByteString) m ZipInfo+unZipStream ::+  ( MonadThrow m+#if MIN_VERSION_conduit(1,3,0)+  , PrimMonad m+#else+  , MonadBase b m, PrimMonad b+#endif+  ) => C.ConduitM BS.ByteString (Either ZipEntry BS.ByteString) m ZipInfo unZipStream = next where   next = do -- local header, or start central directory     h <- sinkGet $ do@@ -151,7 +161,8 @@   centralBody 0x06054b50 = EndOfCentralDirectory <$> endDirectory   centralBody sig = fail $ "Unknown header signature: " ++ show sig   fileHeader = do-    ver <- G.getWord16le+    ver <- G.getWord8+    _os <- G.getWord8 -- OS Version (could require 0 = DOS, but we ignore ext attrs altogether)     when (ver > zipVersion) $ fail $ "Unsupported version: " ++ show ver     gpf <- G.getWord16le     -- when (gpf .&. complement (bit 1 .|. bit 2 .|. bit 3) /= 0) $ fail $ "Unsupported flags: " ++ show gpf
Codec/Archive/Zip/Conduit/Zip.hs view
@@ -1,4 +1,5 @@ -- |Stream the creation of a zip file, e.g., as it's being uploaded.+{-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ViewPatterns #-} module Codec.Archive.Zip.Conduit.Zip@@ -14,7 +15,9 @@ import qualified Codec.Compression.Zlib.Raw as Z import           Control.Arrow ((&&&), (+++), left) import           Control.Monad (when)+#if !MIN_VERSION_conduit(1,3,0) import           Control.Monad.Base (MonadBase)+#endif import           Control.Monad.Catch (MonadThrow) import           Control.Monad.Primitive (PrimMonad) import           Control.Monad.State.Strict (StateT, get)@@ -63,7 +66,7 @@ zipFileData :: MonadResource m => FilePath -> ZipData m zipFileData = ZipDataSource . CB.sourceFile -zipData :: Monad m => ZipData m -> Either (C.Source m BS.ByteString) BSL.ByteString+zipData :: Monad m => ZipData m -> Either (C.ConduitM () BS.ByteString m ()) BSL.ByteString zipData (ZipDataByteString b) = Right b zipData (ZipDataSource s) = Left s @@ -77,7 +80,7 @@   , fromIntegral (year - 1980) `shiftL` 9 .|. fromIntegral month `shiftL` 5 .|. fromIntegral day   ) -countOutput :: Monad m => C.Conduit i m BS.ByteString -> C.Conduit i (StateT Word64 m) BS.ByteString+countOutput :: Monad m => C.ConduitM i BS.ByteString m () -> C.ConduitM i BS.ByteString (StateT Word64 m) () countOutput c = stateC $ \s -> (,) () . (s +) <$> outputSize c  output :: MonadThrow m => P.Put -> C.ConduitM i BS.ByteString (StateT Word64 m) ()@@ -92,7 +95,14 @@ -- -- Depending on options, the resulting zip file should be compatible with most unzipping applications. -- Any errors are thrown in the underlying monad (as 'ZipError's).-zipStream :: (MonadBase b m, PrimMonad b, MonadThrow m) => ZipOptions -> C.ConduitM (ZipEntry, ZipData m) BS.ByteString m Word64+zipStream :: +  ( MonadThrow m+#if MIN_VERSION_conduit(1,3,0)+  , PrimMonad m+#else+  , MonadBase b m, PrimMonad b+#endif+  ) => ZipOptions -> C.ConduitM (ZipEntry, ZipData m) BS.ByteString m Word64 zipStream ZipOptions{..} = execStateC 0 $ do   (cnt, cdir) <- next 0 (return ())   cdoff <- get@@ -129,7 +139,8 @@     off <- get     output $ do       P.putWord32le 0x04034b50-      P.putWord16le $ if z64 then 45 else 20+      P.putWord8 $ if z64 then 45 else 20+      P.putWord8 osVersion       common       P.putWord32le $ fromMaybe 0 mcrc       P.putWord32le $ if z64 then maxBound32 else maybe 0 fromIntegral csiz@@ -165,8 +176,10 @@           l64 = z64 ?* 16 + o64 ?* 8           a64 = z64 || o64       P.putWord32le 0x02014b50-      P.putWord16le zipVersion-      P.putWord16le $ if a64 then 45 else 20+      P.putWord8 zipVersion+      P.putWord8 osVersion+      P.putWord8 $ if a64 then 45 else 20+      P.putWord8 osVersion       common       P.putWord32le crc       P.putWord32le $ if z64 then maxBound32 else fromIntegral csz@@ -192,8 +205,10 @@     when z64 $ output $ do       P.putWord32le 0x06064b50 -- zip64 end       P.putWord64le 44 -- length of this record-      P.putWord16le zipVersion-      P.putWord16le 45+      P.putWord8 zipVersion+      P.putWord8 osVersion+      P.putWord8 45+      P.putWord8 osVersion       P.putWord32le 0 -- disk       P.putWord32le 0 -- central disk       P.putWord64le cnt
cmd/unzip.hs view
@@ -7,6 +7,7 @@ import qualified Data.Conduit as C import qualified Data.Conduit.Binary as CB import           Data.Time.LocalTime (localTimeToUTC, utc)+import           Data.Void (Void) import           System.Directory (createDirectoryIfMissing #if MIN_VERSION_directory(1,2,3)   , setModificationTime@@ -19,7 +20,7 @@  import           Codec.Archive.Zip.Conduit.UnZip -extract :: C.Sink (Either ZipEntry BS.ByteString) IO ()+extract :: C.ConduitM (Either ZipEntry BS.ByteString) Void IO () extract = C.awaitForever start where   start (Left ZipEntry{..}) = do     liftIO $ BSC.putStrLn zipEntryName
cmd/zip.hs view
@@ -10,8 +10,13 @@ import qualified System.Console.GetOpt as Opt import           System.Directory (doesDirectoryExist, getModificationTime #if MIN_VERSION_directory(1,2,6)-  , isSymbolicLink, listDirectory+#if MIN_VERSION_directory(1,3,0)+  , pathIsSymbolicLink #else+  , isSymbolicLink+#endif+  , listDirectory+#else   , getDirectoryContents #endif   )@@ -34,7 +39,7 @@     "set zip comment"   ] -generate :: (MonadIO m, MonadResource m) => [FilePath] -> C.Source m (ZipEntry, ZipData m)+generate :: (MonadIO m, MonadResource m) => [FilePath] -> C.ConduitM () (ZipEntry, ZipData m) m () generate (p:paths) = do   t <- liftIO $ getModificationTime p   let e = ZipEntry@@ -45,10 +50,17 @@   isd <- liftIO $ doesDirectoryExist p   if isd     then do+      dl <- liftIO $ #if MIN_VERSION_directory(1,2,6)-      dl <- liftIO $ filterM (fmap not . isSymbolicLink) . map (p </>) =<< listDirectory p+        filterM (fmap not .+#if MIN_VERSION_directory(1,3,0)+          pathIsSymbolicLink #else-      dl <- liftIO $ filter (`notElem` [".",".."]) . map (p </>) <$> getDirectoryContents p+          isSymbolicLink+#endif+          ) . map (p </>) =<< listDirectory p+#else+        filter (`notElem` [".",".."]) . map (p </>) <$> getDirectoryContents p #endif       C.yield (e{ zipEntryName = zipEntryName e `BSC.snoc` '/', zipEntrySize = Just 0 }, mempty)       generate $ dl ++ paths
zip-stream.cabal view
@@ -1,5 +1,5 @@ name:                zip-stream-version:             0.1.0.1+version:             0.1.1 synopsis:            ZIP archive streaming using conduits description:         Process (extract and create) zip files as streams (e.g., over the network), accessing contained files without having to write the zip file to disk (unlike zip-conduit). license:             BSD3@@ -25,7 +25,7 @@   default-language:    Haskell2010   ghc-options: -Wall   build-depends:       -    base >= 4.8 && < 5,+    base >= 4.9 && < 5,     binary >= 0.7.2,     binary-conduit,     bytestring,