packages feed

dirtree 0.1.1 → 0.1.2

raw patch · 4 files changed

+271/−345 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ System.DirTree: checkFileType :: FilePath -> IO (Maybe FileType)
- System.DirTree: _DirTreeNode :: AsDirTreeNode r_am1U r_aaxx a_aaxy => Prism' r_am1U (DirTreeNode r_aaxx a_aaxy)
+ System.DirTree: _DirTreeNode :: AsDirTreeNode r_amem r_aaBQ a_aaBR => Prism' r_amem (DirTreeNode r_aaBQ a_aaBR)
- System.DirTree: _Directory :: AsDirTreeNode r_am1U r_aaxx a_aaxy => Prism' r_am1U r_aaxx
+ System.DirTree: _Directory :: AsDirTreeNode r_amem r_aaBQ a_aaBR => Prism' r_amem r_aaBQ
- System.DirTree: _File :: AsDirTreeNode r_am1U r_aaxx a_aaxy => Prism' r_am1U a_aaxy
+ System.DirTree: _File :: AsDirTreeNode r_amem r_aaBQ a_aaBR => Prism' r_amem a_aaBR
- System.DirTree: _Real :: AsRelativeFile r_amqK s_am2a a_am2b => Prism' r_amqK a_am2b
+ System.DirTree: _Real :: AsRelativeFile r_amDg s_ameC a_ameD => Prism' r_amDg a_ameD
- System.DirTree: _RelativeFile :: AsRelativeFile r_amqK s_am2a a_am2b => Prism' r_amqK (RelativeFile s_am2a a_am2b)
+ System.DirTree: _RelativeFile :: AsRelativeFile r_amDg s_ameC a_ameD => Prism' r_amDg (RelativeFile s_ameC a_ameD)
- System.DirTree: _Symlink :: AsRelativeFile r_amqK s_am2a a_am2b => Prism' r_amqK s_am2a
+ System.DirTree: _Symlink :: AsRelativeFile r_amDg s_ameC a_ameD => Prism' r_amDg s_ameC
- System.DirTree: class AsDirTreeNode r_am1U r_aaxx a_aaxy | r_am1U -> r_aaxx a_aaxy
+ System.DirTree: class AsDirTreeNode r_amem r_aaBQ a_aaBR | r_amem -> r_aaBQ a_aaBR
- System.DirTree: class AsRelativeFile r_amqK s_am2a a_am2b | r_amqK -> s_am2a a_am2b
+ System.DirTree: class AsRelativeFile r_amDg s_ameC a_ameD | r_amDg -> s_ameC a_ameD

Files

dirtree.cabal view
@@ -1,17 +1,18 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.1.+-- This file has been generated from package.yaml by hpack version 0.33.0. -- -- see: https://github.com/sol/hpack ----- hash: 04b2faaa60c67c8e41c9199e27a349c490f89680aaacffd35aa25967f4984de0+-- hash: eff64c4926d1a5563a628314d1284f818a7d00e225a378f5c3b2b387494a1e32  name:           dirtree-version:        0.1.1+version:        0.1.2 synopsis:       A small library for working with directories. description:    A small library for loading and building directories as trees. category:       System homepage:       https://github.com/kalhauge/dirtree#readme+bug-reports:    https://github.com/kalhauge/dirtree/issues author:         Christian Gram Kalhauge maintainer:     christian@kalhauge.dk copyright:      MIT@@ -20,6 +21,10 @@ build-type:     Simple extra-source-files:     README.md++source-repository head+  type: git+  location: https://github.com/kalhauge/dirtree  library   exposed-modules:
src/System/DirTree.hs view
@@ -22,119 +22,110 @@  -} module System.DirTree- (+  (    -- * 'DirTreeNode'    -- $DirTreeNode--   DirTreeNode (..)- , RelativeFile (..)+    DirTreeNode(..)+  , RelativeFile(..)     -- ** Helpers- , FileType- , fileTypeOfNode-- , AsDirTreeNode (..)- , AsRelativeFile (..)+  , FileType+  , fileTypeOfNode+  , AsDirTreeNode(..)+  , AsRelativeFile(..)     -- ** IO- , getFileType- , readPath+  , getFileType+  , checkFileType+  , readPath     -- * 'FileMap'    -- $FileMap-- , FileMap (..)+  , FileMap(..)   -- ** Constructors- , emptyFileMap- , singletonFileMap- , toFileList- , fromFileList- , (.*), (./), (.*>), (.*.)+  , emptyFileMap+  , singletonFileMap+  , toFileList+  , fromFileList+  , (.*)+  , (./)+  , (.*>)+  , (.*.)   -- ** Accessors- , lookupFileMap+  , lookupFileMap     -- * 'DirTree'    -- $DirTree- , DirTree (..)- , RelativeDirTree- , asRelativeDirTree+  , DirTree(..)+  , RelativeDirTree+  , asRelativeDirTree     -- ** Constructors- , file- , realfile- , symlink- , directory-- , directory'-- , emptyDirectory-- , createDeepFile- , createDeepTree+  , file+  , realfile+  , symlink+  , directory+  , directory'+  , emptyDirectory+  , createDeepFile+  , createDeepTree     -- ** Accessors- , FileKey-- , fileKeyFromPath- , fileKeyToPath-- , diffFileKey- , diffPath-- , alterFile+  , FileKey+  , fileKeyFromPath+  , fileKeyToPath+  , diffFileKey+  , diffPath+  , alterFile     -- ** Iterators    -- Most of the iterators can be done with the 'FunctorWithIndex',    -- 'FoldableWithIndex', and 'TraversableWithIndex', but some accumilations    -- are easier.- , iflattenDirTree- , flattenDirTree-- , depthfirst- , findNode- , listNodes+  , iflattenDirTree+  , flattenDirTree+  , depthfirst+  , findNode+  , listNodes     -- ** IO-- , readDirTree- , writeDirTree- , Link (..)- , toLink- , readRelativeDirTree- , followLinks- , writeRelativeDirTree+  , readDirTree+  , writeDirTree+  , Link(..)+  , toLink+  , readRelativeDirTree+  , followLinks+  , writeRelativeDirTree   -- * 'DirForest'  -- $DirForest-- , DirForest (..)- , RelativeDirForest-- , ForestFileKey- , fromForestFileKey- , toForestFileKey+  , DirForest(..)+  , RelativeDirForest+  , ForestFileKey+  , fromForestFileKey+  , toForestFileKey   -- ** Constructors- , asRelativeDirForest- , emptyForest- , singletonForest- , createDeepForest+  , asRelativeDirForest+  , emptyForest+  , singletonForest+  , createDeepForest   -- ** Iterators- , alterForest-- ) where+  , alterForest+  )+where  -- containers-import qualified Data.Map                 as Map+import qualified Data.Map                      as Map  -- deepseq import           Control.DeepSeq  -- directory-import           System.Directory         hiding (findFile)+import           System.Directory        hiding ( findFile )  -- filepath import           System.FilePath@@ -142,18 +133,20 @@ -- lens import           Control.Lens.Combinators import           Control.Lens--- import           Control.Lens.Indexed  -- base import           Data.Functor import           Data.Foldable import           Data.Bifunctor import           Data.Maybe-import           Data.List.NonEmpty (NonEmpty (..), nonEmpty)-import           Data.Semigroup (sconcat)+import           Data.List.NonEmpty             ( NonEmpty(..)+                                                , nonEmpty+                                                )+import           Data.Semigroup                 ( sconcat ) import           Data.Monoid import           Data.Bitraversable import           Data.Bifoldable+import           System.IO.Error import           Control.Monad import           Text.Show import           GHC.Generics@@ -171,17 +164,17 @@ instance Bifunctor DirTreeNode where   bimap fr fa = \case     Directory r -> Directory (fr r)-    File a -> File (fa a)+    File      a -> File (fa a)  instance Bifoldable DirTreeNode where   bifoldMap fr fa = \case     Directory r -> fr r-    File a -> fa a+    File      a -> fa a  instance Bitraversable DirTreeNode where   bitraverse fr fa = \case     Directory r -> Directory <$> fr r-    File a -> File <$> fa a+    File      a -> File <$> fa a  makeClassyPrisms ''DirTreeNode @@ -195,17 +188,17 @@ instance Bifunctor RelativeFile where   bimap fr fa = \case     Symlink r -> Symlink (fr r)-    Real a -> Real (fa a)+    Real    a -> Real (fa a)  instance Bifoldable RelativeFile where   bifoldMap fr fa = \case     Symlink r -> fr r-    Real a -> fa a+    Real    a -> fa a  instance Bitraversable RelativeFile where   bitraverse fr fa = \case     Symlink r -> Symlink <$> fr r-    Real a -> Real <$> fa a+    Real    a -> Real <$> fa a  makeClassyPrisms ''RelativeFile @@ -224,26 +217,24 @@ getFileType :: FilePath -> IO FileType getFileType fp =   -- TODO: Throw a resonable exception if the file does not exist.-  pathIsSymbolicLink fp >>= \case-  True ->-    return $ File (Symlink ())-  False ->-    doesDirectoryExist fp >>= \case-    True ->-      return $ Directory ()-    False ->-      return $ File (Real ())+                 pathIsSymbolicLink fp >>= \case+  True  -> return $ File (Symlink ())+  False -> doesDirectoryExist fp >>= \case+    True  -> return $ Directory ()+    False -> return $ File (Real ()) +-- | Check a filepath for Type, return Nothing if the path does not+-- exist.+checkFileType :: FilePath -> IO (Maybe FileType)+checkFileType fp =+  catchIOError (Just <$> getFileType fp) (const . return $ Nothing)+ -- | Reads the structure of the filepath-readPath ::-  FilePath-  -> IO (DirTreeNode [String] (RelativeFile FilePath ()))-readPath fp = bitraverse-  (const $ listDirectory fp)-  (bitraverse-   (const $ getSymbolicLinkTarget fp)-   return-  ) =<< getFileType fp+readPath :: FilePath -> IO (DirTreeNode [String] (RelativeFile FilePath ()))+readPath fp =+  bitraverse (const $ listDirectory fp)+             (bitraverse (const $ getSymbolicLinkTarget fp) return)+    =<< getFileType fp   -- $FileMap@@ -258,15 +249,14 @@ singletonFileMap :: String -> a -> FileMap a singletonFileMap s a = FileMap (Map.singleton s a) --- | empty filemap+-- | An empty filemap emptyFileMap :: FileMap a emptyFileMap = FileMap Map.empty  -- | The 'FileMap' is a semigroup if the contnent is. It tries -- to union the content under each item. instance Semigroup a => Semigroup (FileMap a) where-  FileMap as <> FileMap bs =-    FileMap (Map.unionWith (<>) as bs)+  FileMap as <> FileMap bs = FileMap (Map.unionWith (<>) as bs)  -- | The empty monoid is the emptyFileMap instance Semigroup a => Monoid (FileMap a) where@@ -279,21 +269,22 @@   {-# INLINE itraverse #-}  instance Show a => Show (DirForest a) where-  showsPrec d m = showParen (d > 9) $ showString "DirForest . fromFileList " . showFileList m-    where-      showFileList =-        showListWith (\(s, x) -> f s $ dirTreeNode x) . toFileList . getInternalFileMap+  showsPrec d m =+    showParen (d > 9) $ showString "DirForest . fromFileList " . showFileList m+   where+    showFileList =+      showListWith (\(s, x) -> f s $ dirTreeNode x)+        . toFileList+        . getInternalFileMap -      f s (Directory x) =-        showsPrec (dir_prec+1) s .-        showString " ./ "      .-        showFileList x+    f s (Directory x) =+      showsPrec (dir_prec + 1) s . showString " ./ " . showFileList x -      f s (File x) =-        showsPrec (dir_prec+1) s .-        showString " .* "      .-        showsPrec (dir_prec+1) x-      dir_prec = 5+    f s (File x) =+      showsPrec (dir_prec + 1) s+        . showString " .* "+        . showsPrec (dir_prec + 1) x+    dir_prec = 5   -- | Create a list of pairs of filenames and file values.@@ -313,14 +304,13 @@ lookupFileMap s (FileMap a) = Map.lookup s a  -- | The 'Map.alterF' version to the FileMap.-alterFileMap ::-  Functor f+alterFileMap+  :: Functor f   => (Maybe a -> f (Maybe a))   -> String   -> FileMap a   -> f (FileMap a)-alterFileMap fn key (FileMap fm) =-  FileMap <$> Map.alterF fn key fm+alterFileMap fn key (FileMap fm) = FileMap <$> Map.alterF fn key fm  type instance Index (FileMap a) = String type instance IxValue (FileMap a) = a@@ -344,17 +334,11 @@ type DirTreeN a = DirTreeNode (DirForest a) a  -- | A specialized traversal of the DirTreeNode-itraverseDirTreeN ::-  Applicative f-  => (FileKey -> a -> f b)-  -> DirTreeN a-  -> f (DirTreeN b)+itraverseDirTreeN+  :: Applicative f => (FileKey -> a -> f b) -> DirTreeN a -> f (DirTreeN b) itraverseDirTreeN fia = \case-  Directory m ->-    Directory <$> itraverse (fia . fromForestFileKey) m-  File a ->-    File <$> fia [] a-+  Directory m -> Directory <$> itraverse (fia . fromForestFileKey) m+  File      a -> File <$> fia [] a  -- | A dir tree is a tree of nodes. newtype DirTree a = DirTree@@ -362,7 +346,6 @@   }   deriving (Eq, Ord, NFData, Generic) - instance Functor DirTree where   fmap f (DirTree a) = DirTree $ bimap (fmap f) f a @@ -385,15 +368,12 @@ asRelativeDirTree :: DirTree a -> RelativeDirTree s a asRelativeDirTree = fmap Real - instance (Show a) => Show (DirTree a) where-  showsPrec d c = showParen (d >9) (f $ dirTreeNode c)-    where+  showsPrec d c = showParen (d > 9) (f $ dirTreeNode c)+   where     f = \case-      Directory a ->-        showString "directory " . showsPrec 11 a-      File a ->-        showString "file " . showsPrec 11 a+      Directory a -> showString "directory " . showsPrec 11 a+      File      a -> showString "file " . showsPrec 11 a  -- | A DirTree is a semigroup, where it merges directories and take the last -- entry if there files.@@ -456,13 +436,11 @@  -- | Get a `FileKey` from a `FilePath` fileKeyFromPath :: FilePath -> FileKey-fileKeyFromPath =-  splitDirectories+fileKeyFromPath = splitDirectories  -- | Get a `FilePath` from a `FileKey` fileKeyToPath :: FileKey -> FilePath-fileKeyToPath =-  joinPath+fileKeyToPath = joinPath  -- | 'diffFileKey' produces a filepath which is needed to -- navigate from one FileKey to a other.@@ -477,17 +455,12 @@ -- "../../hello" diffFileKey :: FileKey -> FileKey -> FilePath diffFileKey f to' =-  let (n, bs) = prefix f to'-  in fileKeyToPath (replicate n ".." ++ bs)-  where-    prefix al@(a:as) bl@(b:bs)-      | a == b = prefix as bs-      | otherwise =-        (length al, bl)-    prefix (_:as) [] =-      (1 + length as, [])-    prefix [] bs =-      (0, bs)+  let (n, bs) = prefix f to' in fileKeyToPath (replicate n ".." ++ bs)+ where+  prefix al@(a : as) bl@(b : bs) | a == b    = prefix as bs+                                 | otherwise = (length al, bl)+  prefix (_ : as) [] = (1 + length as, [])+  prefix []       bs = (0, bs)  -- | 'diffPath' produces a the filekey at the end of -- a relative filepath, from one filekey.@@ -507,34 +480,32 @@ -- >>> diffPath ["world", "test"] "../../.." -- Nothing diffPath :: FileKey -> FilePath -> Maybe FileKey-diffPath f path-  | isAbsolute path = Nothing-  | otherwise = go (fileKeyFromPath path) (reverse f)-  where-    go = \case-      "..":rest -> \case-        _:as -> go rest as-        [] -> Nothing-      rest -> \m -> Just (reverse m ++ rest)+diffPath f path | isAbsolute path = Nothing+                | otherwise       = go (fileKeyFromPath path) (reverse f)+ where+  go = \case+    ".." : rest -> \case+      _ : as -> go rest as+      []     -> Nothing+    rest -> \m -> Just (reverse m ++ rest)  -- | Alter File is the 'DirTree' version of 'Map.alterF'. -- -- >>> alterFile (\x -> [Nothing, x, Just (file 'b')]) [] (Just (file 'a')) -- [Nothing,Just (file 'a'),Just (file 'b')]-alterFile ::-  forall f a. Functor f+alterFile+  :: forall f a+   . Functor f   => (Maybe (DirTree a) -> f (Maybe (DirTree a)))   -> FileKey   -> Maybe (DirTree a)   -> f (Maybe (DirTree a)) alterFile fn key = maybe (newFile key) (go key) where-  go key' tree@(DirTree node) =-    case key' of-      [] -> fn (Just tree)-      k : rest ->-        case node of-          Directory a -> Just . directory <$> alterForest fn (k :| rest) a-          File _ -> newFile rest+  go key' tree@(DirTree node) = case key' of+    []       -> fn (Just tree)+    k : rest -> case node of+      Directory a -> Just . directory <$> alterForest fn (k :| rest) a+      File      _ -> newFile rest    newFile :: FileKey -> f (Maybe (DirTree a))   newFile key' = fmap (createDeepTree key') <$> fn Nothing@@ -542,28 +513,24 @@  -- | Create a recursive `DirTree` from a FileKey and a value. createDeepFile :: FileKey -> a -> DirTree a-createDeepFile key a =-  createDeepTree key (file a)+createDeepFile key a = createDeepTree key (file a) {-# INLINE createDeepFile #-}  -- | Create a recursive `DirTree` from a FileKey and a value. createDeepTree :: FileKey -> DirTree a -> DirTree a-createDeepTree key a =-  foldr (\s f -> directory (singletonForest s f)) a key+createDeepTree key a = foldr (\s f -> directory (singletonForest s f)) a key {-# INLINE createDeepTree #-}  type instance Index (DirTree a) = FileKey type instance IxValue (DirTree a) = DirTree a  instance Ixed (DirTree a) where-  ix key fn = go key where-    go key' tree@(DirTree node) =-      case nonEmpty key' of-        Nothing -> fn tree-        Just fk ->-          case node of-            Directory a -> directory <$> ix fk fn a-            File _ -> pure tree+  ix key fn = go key   where+    go key' tree@(DirTree node) = case nonEmpty key' of+      Nothing -> fn tree+      Just fk -> case node of+        Directory a -> directory <$> ix fk fn a+        File      _ -> pure tree   {-# INLINE ix #-}  -- | Not a completly correct Lens, since it is implossible to@@ -577,52 +544,43 @@   {-# INLINE at #-}  -- | This method enables eta reduction of a DirTree a with an index.-iflattenDirTree ::-  (FileKey -> DirTreeNode (FileMap m) a -> m)-  -> DirTree a-  -> m+iflattenDirTree :: (FileKey -> DirTreeNode (FileMap m) a -> m) -> DirTree a -> m iflattenDirTree f = go id where   go fk =-    f (fk []) . first (imap (\k -> go (fk . (k:))) . getInternalFileMap) . dirTreeNode-{-# inline iflattenDirTree #-}+    f (fk [])+      . first (imap (\k -> go (fk . (k :))) . getInternalFileMap)+      . dirTreeNode+{-# INLINE iflattenDirTree #-}  -- | This method enables eta reduction of a DirTree a.-flattenDirTree ::-  (DirTreeNode (FileMap m) a -> m)-  -> DirTree a-  -> m-flattenDirTree f = go where-  go = f . first (fmap go . getInternalFileMap) . dirTreeNode-{-# inline flattenDirTree #-}+flattenDirTree :: (DirTreeNode (FileMap m) a -> m) -> DirTree a -> m+flattenDirTree f = go+  where go = f . first (fmap go . getInternalFileMap) . dirTreeNode+{-# INLINE flattenDirTree #-}  -- | Uses a semigroup to join together the results, This is slightly -- less powerfull than 'iflattenDirTree', but more convinient for -- summations.-depthfirst ::-  (Semigroup m)-  => (FileKey -> DirTreeNode [String] a -> m)-  -> DirTree a-  -> m+depthfirst+  :: (Semigroup m) => (FileKey -> DirTreeNode [String] a -> m) -> DirTree a -> m depthfirst f = iflattenDirTree $ \k -> \case-  Directory fm -> sconcat $-    f k (Directory . toFileNames $ fm) :| Data.Foldable.toList fm+  Directory fm ->+    sconcat $ f k (Directory . toFileNames $ fm) :| Data.Foldable.toList fm   File a -> f k (File a)-{-# inline depthfirst #-}+{-# INLINE depthfirst #-}  -- | Find a file given a predicate that takes a `FileKey` and `DirTreeNode`.-findNode ::-  (FileKey -> DirTreeNode [String] a -> Bool)+findNode+  :: (FileKey -> DirTreeNode [String] a -> Bool)   -> DirTree a   -> Maybe (FileKey, DirTreeNode [String] a)-findNode f =-  getFirst . depthfirst (\k a -> First $ guard (f k a) $> (k, a))-{-# inline findNode #-}+findNode f = getFirst . depthfirst (\k a -> First $ guard (f k a) $> (k, a))+{-# INLINE findNode #-}  -- List all the nodes in the dirtree listNodes :: DirTree a -> [(FileKey, DirTreeNode [String] a)]-listNodes =-  (`appEndo` []) . depthfirst (\k a -> Endo ((k, a):))-{-# inline listNodes #-}+listNodes = (`appEndo` []) . depthfirst (\k a -> Endo ((k, a) :))+{-# INLINE listNodes #-}   -- ** IO Methods@@ -636,97 +594,76 @@  -- | Figure out a link from the FileKey and FilePath of Link toLink :: FileKey -> FilePath -> Link-toLink key f =-  maybe (External f) Internal (diffPath (Prelude.init key) f)+toLink key f = maybe (External f) Internal (diffPath (Prelude.init key) f)   -- | Reads a DirTree. All file paths are absolute to the filepath-readRelativeDirTree ::-  (FilePath -> IO a)-  -> FilePath-  -> IO (RelativeDirTree Link a)+readRelativeDirTree+  :: (FilePath -> IO a) -> FilePath -> IO (RelativeDirTree Link a) readRelativeDirTree reader' fp = do   from' <- canonicalizePath fp   go from' fp-  where-    go from' fp' = do-      node <- readPath fp'-      DirTree <$> bimapM-        ( fmap (DirForest . fromFileList) . mapM (\k -> (k,) <$> go from' (fp' </> k)) )-        ( bimapM absolute (const $ reader' fp') )-        node-      where-        absolute a-          | isAbsolute a =-              return $ External a-          | otherwise = do-            a' <- canonicalizePath (takeDirectory fp' </> a)-            let a'' = makeRelative from' a'-            return $ if a'' /= a'-              then Internal (fileKeyFromPath a'')-              else External a'+ where+  go from' fp' = do+    node <- readPath fp'+    DirTree+      <$> bimapM+            ( fmap (DirForest . fromFileList)+            . mapM (\k -> (k, ) <$> go from' (fp' </> k))+            )+            (bimapM absolute (const $ reader' fp'))+            node+   where+    absolute a+      | isAbsolute a = return $ External a+      | otherwise = do+        a' <- canonicalizePath (takeDirectory fp' </> a)+        let a'' = makeRelative from' a'+        return+          $ if a'' /= a' then Internal (fileKeyFromPath a'') else External a'  -- | Reads a DirTree and follow all the relative links. Might recurse forever.-readDirTree ::-  (FilePath -> IO a)-  -> FilePath-  -> IO (DirTree a)-readDirTree fn fp =-  readRelativeDirTree fn fp >>= followLinks fn+readDirTree :: (FilePath -> IO a) -> FilePath -> IO (DirTree a)+readDirTree fn fp = readRelativeDirTree fn fp >>= followLinks fn  -- | Follow the links to create the tree. This function might recurse forever.-followLinks :: forall a. (FilePath -> IO a) -> RelativeDirTree Link a -> IO (DirTree a)+followLinks+  :: forall a . (FilePath -> IO a) -> RelativeDirTree Link a -> IO (DirTree a) followLinks fn tree = go tree where   go = flattenDirTree $ \case     File (Symlink a) -> case a of-      Internal s ->-        case tree ^? ix s of-          Just a' ->-            go a'-          Nothing ->-            error $ "Could not find " ++ show s-                ++ " in the dirtree " ++ show (void tree)-      External s ->-        readDirTree fn s+      Internal s -> case tree ^? ix s of+        Just a' -> go a'+        Nothing ->+          error $ "Could not find " ++ show s ++ " in the dirtree " ++ show+            (void tree)+      External s -> readDirTree fn s -    File (Real a) ->-      return $ file a+    File      (Real a) -> return $ file a -    Directory a ->-      directory . DirForest <$> sequence a+    Directory a        -> directory . DirForest <$> sequence a  -- | Writes a Relative DirTree to a file-writeRelativeDirTree ::-  (FilePath -> a -> IO ())-  -> FilePath-  -> RelativeDirTree Link a-  -> IO ()+writeRelativeDirTree+  :: (FilePath -> a -> IO ()) -> FilePath -> RelativeDirTree Link a -> IO () writeRelativeDirTree writer fp = depthfirst go where   go key = \case-    Directory _ ->-      createDirectory fp'-    File a ->-      case a of-        Symlink (External target) ->-          createFileLink target fp'-        Symlink (Internal key') ->-          createFileLink-          (case (key, key') of-              (_:fk',  _) -> diffFileKey fk' key'-              ([],    []) -> "."-              ([],     _) -> error "Fail"-          ) fp'-        Real a' ->-          writer fp' a'+    Directory _ -> createDirectory fp'+    File      a -> case a of+      Symlink (External target) -> createFileLink target fp'+      Symlink (Internal key'  ) -> createFileLink+        (case (key, key') of+          (_ : fk', _ ) -> diffFileKey fk' key'+          ([]     , []) -> "."+          ([]     , _ ) -> error "Fail"+        )+        fp'+      Real a' -> writer fp' a'     where fp' = fp </> fileKeyToPath key {-# INLINE writeRelativeDirTree #-}  -- | Writes a Relative DirTree to a file-writeDirTree ::-  (FilePath -> a -> IO ())-  -> FilePath-  -> DirTree a-  -> IO ()+writeDirTree :: (FilePath -> a -> IO ()) -> FilePath -> DirTree a -> IO () writeDirTree writer fp = writeRelativeDirTree writer fp . asRelativeDirTree {-# INLINE writeDirTree #-} @@ -752,7 +689,7 @@ instance FoldableWithIndex ForestFileKey DirForest instance TraversableWithIndex ForestFileKey DirForest where   itraverse f (DirForest fs) =-    DirForest <$> itraverse (\k -> itraverse (f . (k:|))) fs+    DirForest <$> itraverse (\k -> itraverse (f . (k :|))) fs   {-# INLINE itraverse #-}  instance Semigroup (DirForest a) where@@ -778,13 +715,11 @@  -- | Creates an singleton forest singletonForest :: String -> DirTree a -> DirForest a-singletonForest k f =-  DirForest $ singletonFileMap k f+singletonForest k f = DirForest $ singletonFileMap k f  -- | Creates an deep file in a forest createDeepForest :: ForestFileKey -> DirTree a -> DirForest a-createDeepForest (k :| rest) f =-  singletonForest k (createDeepTree rest f)+createDeepForest (k :| rest) f = singletonForest k (createDeepTree rest f)  -- | A relative dir forest also exists. type RelativeDirForest s a = DirForest (RelativeFile s a)@@ -798,18 +733,11 @@  instance Ixed (DirForest a) where   ix (k :| key) fn a = DirForest <$> ix k (ix key fn) (getInternalFileMap a)-  --   -- ix key fn . getInternalFileMap-  --   go key' tree@(DirTree node) =-  --     case key' of-  --       [] -> fn tree-  --       k : rest ->-  --         case node of-  --           Directory a -> directory <$> ix k (ix rest fn) a-  --           File _ -> pure tree   {-# INLINE ix #-} -alterForest ::-  forall f a. Functor f+alterForest+  :: forall f a+   . Functor f   => (Maybe (DirTree a) -> f (Maybe (DirTree a)))   -> ForestFileKey   -> DirForest a
src/System/DirTree/Zip.hs view
@@ -15,14 +15,12 @@ -}  module System.DirTree.Zip-  (-    entriesToDirForest+  ( entriesToDirForest   , entriesFromDirForest    -- * Helpers   , entryToDirForest   , entryFromFile-   , files   , entries     -- * Re-Exports@@ -31,78 +29,72 @@   ) where + -- base-import Data.Foldable-import Data.Maybe-import Data.Bits-import System.Posix.Files (symbolicLinkMode, stdFileMode)+import           Data.Foldable+import           Data.Maybe+import           Data.Bits+import           System.Posix.Files             ( symbolicLinkMode+                                                , stdFileMode+                                                )  -- lens-import Control.Lens+import           Control.Lens  -- zip-archive-import Codec.Archive.Zip+import           Codec.Archive.Zip  -- dirtree-import System.DirTree+import           System.DirTree  -- bytestring-import qualified Data.ByteString.Lazy as BL-import qualified Data.ByteString.Lazy.Char8 as BLC+import qualified Data.ByteString.Lazy          as BL+import qualified Data.ByteString.Lazy.Char8    as BLC   -- | Convert a entry to a single filemap, fails if the entry path is empty.-entryToDirForest ::-  Entry-  -> Maybe (DirForest Entry)-entryToDirForest e =-  flip createDeepForest (file e)+entryToDirForest :: Entry -> Maybe (DirForest Entry)+entryToDirForest e = flip createDeepForest (file e)   <$> toForestFileKey (fileKeyFromPath (eRelativePath e))  -- | Convert entries to a 'FileMap' of 'RelativeDirTree'-entriesToDirForest ::-  [Entry]-  -> Maybe (RelativeDirForest Link BL.ByteString)-entriesToDirForest =-  fmap (imap parseEntry . fold)-  . traverse entryToDirForest-  where-    parseEntry key e =-      case symbolicLinkEntryTarget e of-        Just f -> Symlink . toLink (fromForestFileKey key) $ f-        Nothing -> Real $ fromEntry e+entriesToDirForest :: [Entry] -> Maybe (RelativeDirForest Link BL.ByteString)+entriesToDirForest = fmap (imap parseEntry . fold) . traverse entryToDirForest+ where+  parseEntry key e = case symbolicLinkEntryTarget e of+    Just f  -> Symlink . toLink (fromForestFileKey key) $ f+    Nothing -> Real $ fromEntry e  -- | Create a single entry from a file. This also handles symlinks, but changes -- saves all files with the 'stdFileMode'. entryFromFile :: Integer -> FileKey -> RelativeFile Link BL.ByteString -> Entry entryFromFile i key = \case-  Real bs -> toEntry (fileKeyToPath key) i bs-  Symlink x ->-    toSymlinkEntry (fileKeyToPath key) $ case x of-      Internal trgt -> diffFileKey (init key) trgt-      External f -> f-  where-    toSymlinkEntry path t =-      let e = toEntry path i (BLC.pack t)-      in e { eExternalFileAttributes =-             eExternalFileAttributes e .|. shiftL (fromIntegral ( symbolicLinkMode .|. stdFileMode)) 16-           , eVersionMadeBy = 798 -- Random high number-           }+  Real    bs -> toEntry (fileKeyToPath key) i bs+  Symlink x  -> toSymlinkEntry (fileKeyToPath key) $ case x of+    Internal trgt -> diffFileKey (init key) trgt+    External f    -> f+ where+  toSymlinkEntry path t =+    let e           = toEntry path i (BLC.pack t)+        shiftlength = fromIntegral (symbolicLinkMode .|. stdFileMode)+    in  e+          { eExternalFileAttributes = eExternalFileAttributes e+                                        .|. shiftL shiftlength 16+          , eVersionMadeBy          = 798 -- Random high number+          }  -- | Create a list of enties from a FileMap.-entriesFromDirForest ::-  Integer-  -> RelativeDirForest Link BL.ByteString-  -> [Entry]-entriesFromDirForest i =-  toList . imap (\k -> entryFromFile i (fromForestFileKey k))+entriesFromDirForest+  :: Integer -> RelativeDirForest Link BL.ByteString -> [Entry]+entriesFromDirForest i = toList . imap (entryFromFile i . fromForestFileKey)  -- | A simple lens into the entries of an archive. entries :: Lens' Archive [Entry] entries = lens zEntries (\a b -> a { zEntries = b })  -- | A list of entries can be seen as a FileMap of-entriesAsDirForest :: Integer -> Iso' [Entry] (RelativeDirForest Link BL.ByteString)+entriesAsDirForest+  :: Integer -> Iso' [Entry] (RelativeDirForest Link BL.ByteString) entriesAsDirForest i = iso from' to' where   from' = fromJust . entriesToDirForest   to'   = entriesFromDirForest i
test/System/DirTreeSpec.hs view
@@ -12,7 +12,8 @@  spec :: Spec spec = do-  possibleSpec+  return () +  -- possibleSpec  possibleSpec :: Spec possibleSpec = do