{-# LANGUAGE FlexibleContexts #-} module Main where import Prelude as P import Conduit import Control.Monad (void, when, zipWithM_) import Test.Hspec import Data.Conduit.Tar import System.Directory import Data.ByteString as S import System.IO import System.FilePath import Control.Exception main :: IO () main = do let baseTmp = "tar-conduit-tests" isStack <- doesDirectoryExist ".stack-work" let testPaths = ["src", "./tests", "README.md", "ChangeLog.md", "LICENSE"] ++ if isStack then [".stack-work", "./sample"] else [] hspec $ do describe "tar/untar" $ do let tarUntarContent dir = runConduitRes $ yield dir .| void tarFilePath .| untar (const (foldC >>= yield)) .| foldC it "content" $ do c <- collectContent "src" tarUntarContent "src" `shouldReturn` c describe "tar/untar/tar" $ do around (withTempTarFiles baseTmp) $ it "structure" $ \(fpIn, hIn, outDir, fpOut) -> do writeTarball hIn testPaths hClose hIn extractTarball fpIn (Just outDir) curDir <- getCurrentDirectory finally (setCurrentDirectory outDir >> createTarball fpOut testPaths) (setCurrentDirectory curDir) tb1 <- readTarball fpIn tb2 <- readTarball fpOut P.length tb1 `shouldBe` P.length tb2 zipWithM_ shouldBe (fmap fst tb2) (fmap fst tb1) zipWithM_ shouldBe (fmap snd tb2) (fmap snd tb1) withTempTarFiles :: FilePath -> ((FilePath, Handle, FilePath, FilePath) -> IO c) -> IO c withTempTarFiles base = bracket (do tmpDir <- getTemporaryDirectory (fp1, h1) <- openBinaryTempFile tmpDir (addExtension base ".tar") let outPath = dropExtension fp1 ++ ".out" return (fp1, h1, outPath, addExtension outPath ".tar") ) (\(fp, h, dirOut, fpOut) -> do hClose h removeFile fp doesDirectoryExist dirOut >>= (`when` removeDirectoryRecursive dirOut) doesFileExist fpOut >>= (`when` removeFile fpOut) ) readTarball :: (MonadIO m, MonadThrow m, MonadBaseControl IO m) => FilePath -> m [(FileInfo, Maybe ByteString)] readTarball fp = runConduitRes $ sourceFileBS fp .| untar grabBoth .| sinkList where grabBoth fi = case fileType fi of FTNormal -> do content <- foldC yield (fi, Just content) _ -> yield (fi, Nothing) collectContent :: FilePath -> IO (ByteString) collectContent dir = runConduitRes $ sourceDirectoryDeep False dir .| mapMC (\fp -> runConduit (sourceFileBS fp .| foldC)) .| foldC