packages feed

find-conduit 0.4.1 → 0.4.3

raw patch · 5 files changed

+291/−126 lines, 5 filesdep +conduit-extradep +streaming-commonsdep +unix-compatdep ~basedep ~filepathdep ~unixnew-component:exe:find-hsPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: conduit-extra, streaming-commons, unix-compat

Dependency ranges changed: base, filepath, unix

API changes (from Hackage documentation)

- Data.Conduit.Find: filenameS_ :: Monad m => (String -> Bool) -> CondT FileEntry m ()
- Data.Conduit.Find: findFilesSource :: (MonadIO m, MonadResource m) => FindOptions -> FilePath -> CondT FileEntry m a -> Producer m (FileEntry, a)
- Data.Conduit.Find: ignoreReaddirRace_ :: Monad m => CondT FileEntry m ()
- Data.Conduit.Find: noIgnoreReaddirRace_ :: Monad m => CondT FileEntry m ()
- Data.Conduit.Find: pathnameS_ :: Monad m => (String -> Bool) -> CondT FileEntry m ()
+ Data.Cond: instance MonadMask m => MonadMask (CondT a m)
+ Data.Conduit.Find: FindOptions :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> FindOptions
+ Data.Conduit.Find: data FindOptions
+ Data.Conduit.Find: defaultFindOptions :: FindOptions
+ Data.Conduit.Find: findContentsFirst :: FindOptions -> !Bool
+ Data.Conduit.Find: findFollowSymlinks :: FindOptions -> !Bool
+ Data.Conduit.Find: findIgnoreErrors :: FindOptions -> !Bool
+ Data.Conduit.Find: findIgnoreResults :: FindOptions -> !Bool
+ Data.Conduit.Find: findLeafOptimization :: FindOptions -> !Bool
+ Data.Conduit.Find: ignoreErrors_ :: Monad m => CondT FileEntry m ()
+ Data.Conduit.Find: noIgnoreErrors_ :: Monad m => CondT FileEntry m ()
+ Data.Conduit.Find: noleaf_ :: Monad m => CondT FileEntry m ()
+ Data.Conduit.Find: sourceFindFiles :: (MonadIO m, MonadResource m) => FindOptions -> FilePath -> CondT FileEntry m a -> Producer m (FileEntry, a)
- Data.Conduit.Find: (=~) :: FilePath -> Text -> Bool
+ Data.Conduit.Find: (=~) :: (RegexMaker Regex CompOption ExecOption source, RegexContext Regex source1 target) => source1 -> source -> target
- Data.Conduit.Find: FileEntry :: !FilePath -> !Int -> !(FindOptions) -> !(Maybe FileStatus) -> FileEntry
+ Data.Conduit.Find: FileEntry :: !FilePath -> !Int -> !FindOptions -> !(Maybe FileStatus) -> FileEntry
- Data.Conduit.Find: entryFindOptions :: FileEntry -> !(FindOptions)
+ Data.Conduit.Find: entryFindOptions :: FileEntry -> !FindOptions
- Data.Conduit.Find: glob :: Monad m => Text -> CondT FileEntry m ()
+ Data.Conduit.Find: glob :: Monad m => String -> CondT FileEntry m ()
- Data.Conduit.Find: regex :: Monad m => Text -> CondT FileEntry m ()
+ Data.Conduit.Find: regex :: Monad m => String -> CondT FileEntry m ()

Files

Data/Cond.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE CPP #-}  module Data.Cond     ( CondT(..), Cond@@ -244,6 +245,10 @@  instance MonadCatch m => MonadCatch (CondT a m) where     catch (CondT m) c = CondT $ m `catch` \e -> getCondT (c e)+#if MIN_VERSION_exceptions(0,6,0)++instance MonadMask m => MonadMask (CondT a m) where+#endif     mask a = CondT $ mask $ \u -> getCondT (a $ q u)       where q u = CondT . u . getCondT     uninterruptibleMask a =@@ -262,7 +267,17 @@     lift m = CondT $ liftM accept' $ lift m     {-# INLINE lift #-} +#if MIN_VERSION_monad_control(1,0,0) instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where+    type StM (CondT r m) a = StM m (Result r m a, r)+    liftBaseWith f = CondT $ StateT $ \s ->+        liftM (\x -> (accept' x, s)) $ liftBaseWith $ \runInBase -> f $ \k ->+            runInBase $ runStateT (getCondT k) s+    restoreM = CondT . StateT . const . restoreM+    {-# INLINE liftBaseWith #-}+    {-# INLINE restoreM #-}+#else+instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where     newtype StM (CondT r m) a =         CondTStM { unCondTStM :: StM m (Result r m a, r) }     liftBaseWith f = CondT $ StateT $ \s ->@@ -271,6 +286,7 @@     restoreM = CondT . StateT . const . restoreM . unCondTStM     {-# INLINE liftBaseWith #-}     {-# INLINE restoreM #-}+#endif  instance MFunctor (CondT a) where     hoist nat (CondT m) = CondT $ hoist nat (liftM (hoist nat) m)
Data/Conduit/Find.hs view
@@ -1,7 +1,10 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE ScopedTypeVariables #-}  module Data.Conduit.Find     (@@ -18,10 +21,12 @@     -- $notes      -- * Finding functions-      find-    , findFilesSource+      sourceFindFiles+    , find     , findFiles     , findFilePaths+    , FindOptions(..)+    , defaultFindOptions     , test     , ltest     , stat@@ -35,10 +40,13 @@        -- * GNU find compatibility predicates     , depth_+    , follow_+    , noleaf_+    , prune_     , maxdepth_     , mindepth_-    , ignoreReaddirRace_-    , noIgnoreReaddirRace_+    , ignoreErrors_+    , noIgnoreErrors_     , amin_     , atime_     , anewer_@@ -48,12 +56,8 @@     , name_     , getDepth     , filename_-    , filenameS_     , pathname_-    , pathnameS_     , getFilePath-    , follow_-    , prune_      -- * File entry predicates (uses stat information)     , regular@@ -74,24 +78,29 @@ import           Conduit import           Control.Applicative import           Control.Exception-import           Control.Monad hiding (forM_)+import           Control.Monad hiding (forM_, forM) import           Control.Monad.Morph import           Control.Monad.State.Class import           Data.Attoparsec.Text as A import           Data.Bits import qualified Data.Cond as Cond import           Data.Cond hiding (test)-import           Data.Foldable hiding (elem, find)-import           Data.Maybe (fromMaybe)+import qualified Data.Conduit.Filesystem as CF+#if LEAFOPT+import           Data.IORef+#endif+import           Data.Maybe (fromMaybe,fromJust) import           Data.Monoid import           Data.Text (Text, unpack, pack) import           Data.Time import           Data.Time.Clock.POSIX-import           Filesystem.Path.CurrentOS (FilePath, encodeString, filename)+import           Filesystem.Path.CurrentOS (FilePath,+                                            encodeString, decodeString) import           Prelude hiding (FilePath)-import           System.Posix.Files-import           System.Posix.Types-import qualified Text.Regex.Posix as R ((=~))+import qualified System.FilePath as FP+import           System.PosixCompat.Files+import           System.PosixCompat.Types+import           Text.Regex.Posix ((=~))  {- $intro @@ -189,50 +198,46 @@ -}  data FindOptions = FindOptions-    { findFollowSymlinks    :: Bool-    , findContentsFirst     :: Bool-    , findIgnoreReaddirRace :: Bool-    , findIgnoreResults     :: Bool+    { findFollowSymlinks   :: !Bool+    , findContentsFirst    :: !Bool+    , findIgnoreErrors     :: !Bool+    , findIgnoreResults    :: !Bool+    , findLeafOptimization :: !Bool     }  defaultFindOptions :: FindOptions defaultFindOptions = FindOptions-    { findFollowSymlinks    = True-    , findContentsFirst     = False-    , findIgnoreReaddirRace = False-    , findIgnoreResults     = False+    { findFollowSymlinks   = True+    , findContentsFirst    = False+    , findIgnoreErrors     = False+    , findIgnoreResults    = False+    , findLeafOptimization = True     }  data FileEntry = FileEntry-    { entryPath        :: !FilePath+    { entryPath        :: !FP.FilePath     , entryDepth       :: !Int-    , entryFindOptions :: !(FindOptions)+    , entryFindOptions :: !FindOptions     , entryStatus      :: !(Maybe FileStatus)       -- ^ This is Nothing until we determine stat should be called.     } -newFileEntry :: FilePath -> Int -> FindOptions -> FileEntry-newFileEntry p d f = FileEntry p d f Nothing+newFileEntry :: FP.FilePath -> Int -> FindOptions -> FileEntry+newFileEntry fp d f = FileEntry fp d f Nothing  instance Show FileEntry where     show entry = "FileEntry "               ++ show (entryPath entry)               ++ " " ++ show (entryDepth entry) -getFilePath :: Monad m => CondT FileEntry m FilePath+getFilePath :: Monad m => CondT FileEntry m FP.FilePath getFilePath = gets entryPath -pathname_ :: Monad m => (FilePath -> Bool) -> CondT FileEntry m ()+pathname_ :: Monad m => (FP.FilePath -> Bool) -> CondT FileEntry m () pathname_ f = guard . f =<< getFilePath -pathnameS_ :: Monad m => (String -> Bool) -> CondT FileEntry m ()-pathnameS_ f = pathname_ (f . encodeString)--filename_ :: Monad m => (FilePath -> Bool) -> CondT FileEntry m ()-filename_ f = pathname_ (f . filename)--filenameS_ :: Monad m => (String -> Bool) -> CondT FileEntry m ()-filenameS_ f = pathname_ (f . encodeString . filename)+filename_ :: Monad m => (FP.FilePath -> Bool) -> CondT FileEntry m ()+filename_ f = pathname_ (f . FP.takeFileName)  getDepth :: Monad m => CondT FileEntry m Int getDepth = gets entryDepth@@ -253,23 +258,26 @@ follow_ :: Monad m => CondT FileEntry m () follow_ = modifyFindOptions $ \opts -> opts { findFollowSymlinks = True } -ignoreReaddirRace_ :: Monad m => CondT FileEntry m ()-ignoreReaddirRace_ =-    modifyFindOptions $ \opts -> opts { findIgnoreReaddirRace = True }+noleaf_ :: Monad m => CondT FileEntry m ()+noleaf_ = modifyFindOptions $ \opts -> opts { findLeafOptimization = False } -noIgnoreReaddirRace_ :: Monad m => CondT FileEntry m ()-noIgnoreReaddirRace_ =-    modifyFindOptions $ \opts -> opts { findIgnoreReaddirRace = False }+prune_ :: Monad m => CondT a m ()+prune_ = prune +ignoreErrors_ :: Monad m => CondT FileEntry m ()+ignoreErrors_ =+    modifyFindOptions $ \opts -> opts { findIgnoreErrors = True }++noIgnoreErrors_ :: Monad m => CondT FileEntry m ()+noIgnoreErrors_ =+    modifyFindOptions $ \opts -> opts { findIgnoreErrors = False }+ maxdepth_ :: Monad m => Int -> CondT FileEntry m () maxdepth_ l = getDepth >>= guard . (<= l)  mindepth_ :: Monad m => Int -> CondT FileEntry m () mindepth_ l = getDepth >>= guard . (>= l) -prune_ :: Monad m => CondT a m ()-prune_ = prune- -- xdev_ = error "NYI"  timeComp :: MonadIO m@@ -285,7 +293,7 @@ atime_ :: MonadIO m => Int -> CondT FileEntry m () atime_ n = timeComp lastAccessed_ (n * 24 * 3600) -anewer_ :: MonadIO m => FilePath -> CondT FileEntry m ()+anewer_ :: MonadIO m => FP.FilePath -> CondT FileEntry m () anewer_ path = do     e  <- get     es <- applyStat Nothing@@ -296,7 +304,7 @@         Nothing     -> prune >> error "This is never reached"         Just (s, _) -> guard $ diffUTCTime (f s) (f es) > 0   where-    f = posixSecondsToUTCTime . accessTimeHiRes+    f = posixSecondsToUTCTime . realToFrac . accessTime  -- cmin_ = error "NYI" -- cnewer_ = error "NYI"@@ -326,7 +334,7 @@ mtime_ -} -name_ :: Monad m => FilePath -> CondT FileEntry m ()+name_ :: Monad m => FP.FilePath -> CondT FileEntry m () name_ = filename_ . (==)  {-@@ -351,6 +359,16 @@  ------------------------------------------------------------------------ +statFilePath :: Bool -> Bool -> FP.FilePath -> IO (Maybe FileStatus)+statFilePath follow ignoreErrors path = do+    let doStat = (if follow+                  then getFileStatus+                  else getSymbolicLinkStatus) path+    catch (Just <$> doStat) $ \e ->+        if ignoreErrors+        then return Nothing+        else throwIO (e :: IOException)+ -- | Get the current status for the file.  If the status being requested is --   already cached in the entry information, simply return it from there. getStat :: MonadIO m@@ -364,25 +382,21 @@         | otherwise -> fmap (, entry) `liftM` wrapStat     Nothing -> do         ms <- wrapStat-        case ms of-            Just s  -> return $ Just (s, entry { entryStatus = Just s })-            Nothing -> return Nothing+        return $ case ms of+            Just s  -> Just (s, entry { entryStatus = Just s })+            Nothing -> Nothing   where-    follow = findFollowSymlinks . entryFindOptions-    doStat = (if fromMaybe (follow entry) mfollow-              then getFileStatus-              else getSymbolicLinkStatus) $ encodeString (entryPath entry)-    wrapStat = liftIO $ catch (Just <$> doStat) $ \e ->-        if findIgnoreReaddirRace opts-        then return Nothing-        else throwIO (e :: IOException)+    follow   = findFollowSymlinks . entryFindOptions+    wrapStat = liftIO $ statFilePath+        (fromMaybe (findFollowSymlinks opts) mfollow)+        (findIgnoreErrors opts)+        (entryPath entry)       where         opts = entryFindOptions entry  applyStat :: MonadIO m => Maybe Bool -> CondT FileEntry m FileStatus applyStat mfollow = do-    e <- get-    ms <- lift (getStat mfollow e)+    ms <- lift . getStat mfollow =<< get     case ms of         Nothing      -> prune >> error "This is never reached"         Just (s, e') -> s <$ put e'@@ -409,32 +423,17 @@ hasMode m = hasStatus (\s -> fileMode s .&. m /= 0)  withStatusTime :: MonadIO m-               => (FileStatus -> POSIXTime) -> (UTCTime -> Bool)+               => (FileStatus -> EpochTime) -> (UTCTime -> Bool)                -> CondT FileEntry m ()-withStatusTime g f = hasStatus (f . posixSecondsToUTCTime . g)+withStatusTime g f = hasStatus (f . posixSecondsToUTCTime . realToFrac . g)  lastAccessed_ :: MonadIO m => (UTCTime -> Bool) -> CondT FileEntry m ()-lastAccessed_ = withStatusTime accessTimeHiRes+lastAccessed_ = withStatusTime accessTime  lastModified_ :: MonadIO m => (UTCTime -> Bool) -> CondT FileEntry m ()-lastModified_ = withStatusTime modificationTimeHiRes---- | This is a re-export of 'Text.Regex.Posix.=~', with the types changed for---   use with this module.  For example, you can simply say:------ @---    filename_ (=~ \"\\\\.hs$\")--- @------ Which is the same thing as:------ @---    regex \"\\\\.hs$\"--- @-(=~) :: FilePath -> Text -> Bool-str =~ pat = encodeString str R.=~ unpack pat+lastModified_ = withStatusTime modificationTime -regex :: Monad m => Text -> CondT FileEntry m ()+regex :: Monad m => String -> CondT FileEntry m () regex pat = filename_ (=~ pat)  -- | Return all entries, except for those within version-control metadata@@ -446,10 +445,10 @@  -- | Find every entry whose filename part matching the given filename globbing --   expression.  For example: @glob "*.hs"@.-glob :: Monad m => Text -> CondT FileEntry m ()-glob g = case parseOnly globParser g of+glob :: Monad m => String -> CondT FileEntry m ()+glob g = case parseOnly globParser (pack g) of     Left e  -> error $ "Failed to parse glob: " ++ e-    Right x -> regex ("^" <> x <> "$")+    Right x -> regex ("^" <> unpack x <> "$")   where     globParser :: Parser Text     globParser = fmap mconcat $ many $@@ -462,47 +461,115 @@                 <*> char ']'         <|> do             x <- anyChar-            return . pack $ if x `elem` ".()^$"+            return . pack $ if x `elem` (".()^$" :: String)                             then ['\\', x]                             else [x] +#if LEAFOPT+type DirCounter = IORef LinkCount++newDirCounter :: MonadIO m => m DirCounter+newDirCounter = liftIO $ newIORef 1+#else+type DirCounter = ()++newDirCounter :: MonadIO m => m DirCounter+newDirCounter = return ()+#endif+ -- | Find file entries in a directory tree, recursively, applying the given --   recursion predicate to the search.  This conduit yields pairs of type --   @(FileEntry, a)@, where is the return value from the predicate at each --   step.-findFilesSource :: (MonadIO m, MonadResource m)+sourceFindFiles :: (MonadIO m, MonadResource m)                 => FindOptions                 -> FilePath                 -> CondT FileEntry m a                 -> Producer m (FileEntry, a)-findFilesSource opts startPath predicate =-    wrap $ go (newFileEntry startPath 0 opts) $ hoist lift predicate+sourceFindFiles findOptions startPath predicate = do+    startDc <- newDirCounter+    walk startDc+        (newFileEntry (encodeString startPath) 0 findOptions)+        (encodeString startPath)+        predicate   where-    wrap = mapInput (const ()) (const Nothing)--    go x pr = do-        ((mres, mcond), entry) <- applyCondT x pr+    walk :: MonadResource m+         => DirCounter+         -> FileEntry+         -> FP.FilePath+         -> CondT FileEntry m a+         -> Producer m (FileEntry, a)+    walk !dc !entry !path !cond = do+        ((!mres, !mcond), !entry') <- lift $ applyCondT entry cond         let opts' = entryFindOptions entry-            this  = unless (findIgnoreResults opts') $ yieldEntry entry mres-            next  = walkChildren entry mcond+            this  = unless (findIgnoreResults opts') $+                        yieldEntry entry' mres+            next  = walkChildren dc entry' path mcond         if findContentsFirst opts'             then next >> this             else this >> next+      where+        yieldEntry _      Nothing    = return ()+        yieldEntry entry' (Just res) = yield (entry', res) -    yieldEntry entry mres =-        -- If the item matched, also yield the predicate's result value.-        forM_ mres $ yield . (entry,)+    walkChildren :: MonadResource m+                 => DirCounter+                 -> FileEntry+                 -> FP.FilePath+                 -> Maybe (CondT FileEntry m a)+                 -> Producer m (FileEntry, a)+    walkChildren _ _ _ Nothing = return ()+    -- If the conditional matched, we are requested to recurse if this is a+    -- directory+    walkChildren !dc !entry !path (Just !cond) = do+        st <- lift $ checkIfDirectory dc entry path+        when (fmap isDirectory st == Just True) $ do+#if LEAFOPT+            -- Update directory count for the parent directory.+            liftIO $ modifyIORef dc pred+            -- Track the directory count for this child path.+            let leafOpt = findLeafOptimization (entryFindOptions entry)+            let lc = linkCount (fromJust st) - 2+                opts' = (entryFindOptions entry)+                    { findLeafOptimization = leafOpt && lc >= 0+                    }+            dc' <- liftIO $ newIORef lc+#else+            let dc'   = dc+                opts' = entryFindOptions entry+#endif+            CF.sourceDirectory path =$= awaitForever (go dc' opts')+      where+        go dc' opts' fp =+            let entry' = newFileEntry fp (succ (entryDepth entry)) opts'+            in walk dc' entry' fp cond -    walkChildren entry@(FileEntry path depth opts' _) mcond =-        -- If the conditional matched, we are requested to recurse if this-        -- is a directory-        forM_ mcond $ \cond -> do-            -- If no status has been determined, we must do so now in order-            -- to know whether to actually recurse or not.-            descend <- fmap (isDirectory . fst) <$> getStat Nothing entry-            when (descend == Just True) $-                (sourceDirectory path =$) $ awaitForever $ \fp ->-                    wrap $ go (newFileEntry fp (succ depth) opts') cond+    -- Return True if the given entry is a directory.  We can sometimes use+    -- "leaf optimization" on Linux to answer this question without performing+    -- a stat call.  This is possible because the link count of a directory is+    -- two more than the number of sub-directories it contains, so we've seen+    -- that many sub-directories, the remaining entries must be files.+    checkIfDirectory :: MonadResource m+                     => DirCounter+                     -> FileEntry+                     -> FP.FilePath+                     -> m (Maybe FileStatus)+    checkIfDirectory !dc !entry !path = do+#if LEAFOPT+        let leafOpt = findLeafOptimization (entryFindOptions entry)+        doStat <- if leafOpt+                  then (> 0) <$> liftIO (readIORef dc)+                  else return True+#else+        let doStat = dc == () -- to quiet hlint warnings+#endif+        let opts = entryFindOptions entry+        if doStat+            then liftIO $ statFilePath+                (findFollowSymlinks opts)+                (findIgnoreErrors opts)+                path+            else return Nothing  findFiles :: (MonadIO m, MonadBaseControl IO m, MonadThrow m)           => FindOptions@@ -510,9 +577,9 @@           -> CondT FileEntry m a           -> m () findFiles opts path predicate =-    runResourceT $ findFilesSource-        opts { findIgnoreResults = True } path (hoist lift predicate)-        $$ sinkNull+    runResourceT $+        sourceFindFiles opts { findIgnoreResults = True } path+            (hoist lift predicate) $$ sinkNull  -- | A simpler version of 'findFiles', which yields only 'FilePath' values, --   and ignores any values returned by the predicate action.@@ -522,7 +589,8 @@               -> CondT FileEntry m a               -> Producer m FilePath findFilePaths opts path predicate =-    findFilesSource opts path predicate =$= mapC (entryPath . fst)+    mapOutput decodeString $+        sourceFindFiles opts path predicate =$= mapC (entryPath . fst)  -- | Calls 'findFilePaths' with the default set of finding options. --   Equivalent to @findFilePaths defaultFindOptions@.@@ -534,11 +602,13 @@ --   'findFiles'. test :: MonadIO m => CondT FileEntry m () -> FilePath -> m Bool test matcher path =-    Cond.test (newFileEntry path 0 defaultFindOptions) matcher+    Cond.test (newFileEntry (encodeString path) 0 defaultFindOptions) matcher  -- | Test a file path using the same type of predicate that is accepted by --   'findFiles', but do not follow symlinks. ltest :: MonadIO m => CondT FileEntry m () -> FilePath -> m Bool-ltest matcher path = Cond.test-    (newFileEntry path 0 defaultFindOptions { findFollowSymlinks = False })-    matcher+ltest matcher path =+    Cond.test+        (newFileEntry (encodeString path) 0 defaultFindOptions+            { findFollowSymlinks = False })+        matcher
find-conduit.cabal view
@@ -1,5 +1,5 @@ Name:                find-conduit-Version:             0.4.1+Version:             0.4.3 Synopsis:            A file-finding conduit that allows user control over traversals. License-file:        LICENSE License:             MIT@@ -16,27 +16,36 @@   type: git   location: git://github.com/jwiegley/find-conduit.git +Flag leafopt+  Description: Enable leaf optimization+  Default: True+ Library     default-language:   Haskell98-    ghc-options: -Wall+    ghc-options: -Wall -O2 -funbox-strict-fields+    if os(linux) && flag(leafopt)+        cpp-options: -DLEAFOPT=1     build-depends:         base                 >= 3 && < 5       , conduit+      , conduit-extra       , conduit-combinators       , attoparsec       , system-filepath-      , unix                 >= 2.5.1.1+      , unix-compat          >= 0.4.1.1       , text                 >= 0.11.3.1       , regex-posix       , mtl       , semigroups       , exceptions       , time+      , streaming-commons       , transformers       , transformers-base       , mmorph       , either       , monad-control+      , filepath     exposed-modules:         Data.Cond, Data.Conduit.Find @@ -53,18 +62,20 @@       , conduit-combinators       , attoparsec       , system-filepath-      , unix                 >= 2.5.1.1+      , unix-compat          >= 0.4.1.1       , text                 >= 0.11.3.1       , regex-posix       , mtl       , time       , either       , semigroups+      , streaming-commons       , exceptions       , transformers       , transformers-base       , monad-control       , mmorph+      , filepath       , hspec                >= 1.4  Test-suite doctests@@ -73,9 +84,36 @@     Main-is: doctest.hs     Hs-source-dirs: test     Build-depends:      -          base-        , directory    >= 1.0-        , doctest      >= 0.8-        , filepath     >= 1.3-        , semigroups   >= 0.4+        base+      , directory    >= 1.0+      , doctest      >= 0.8+      , filepath     >= 1.3+      , semigroups   >= 0.4 +Executable find-hs+    Main-is:     find-hs.hs+    default-language:   Haskell2010+    Ghc-options: -threaded -O2+    Hs-source-dirs: test+    Build-depends:+        base+      , find-conduit+      , conduit+      , conduit-extra+      , conduit-combinators+      , attoparsec+      , system-filepath+      , unix                 >= 0.4.1.1+      , text                 >= 0.11.3.1+      , regex-posix+      , mtl+      , time+      , either+      , semigroups+      , streaming-commons+      , exceptions+      , transformers+      , transformers-base+      , monad-control+      , mmorph+      , filepath
test/doctest.hs view
@@ -11,7 +11,6 @@ main = getSources >>= \sources -> doctest $     "-iData"   : "-idist/build/autogen"-  : "-package=semigroups-0.13.0.1"   : "-optP-include"   : "-optPdist/build/autogen/cabal_macros.h"   : sources
+ test/find-hs.hs view
@@ -0,0 +1,42 @@+module Main where++import Conduit+import Control.Monad+import Control.Monad.Reader.Class+import Data.Conduit.Find+import Data.List+import Filesystem.Path.CurrentOS+import System.Environment+import System.Posix.Process++main :: IO ()+main = do+    [command, dir] <- getArgs+    case command of+        "conduit" -> do+            putStrLn "Running sourceDirectoryDeep from conduit-extra"+            runResourceT $+                sourceDirectoryDeep False (decodeString dir)+                    =$ filterC ((".hs" `isSuffixOf`) . encodeString)+                    $$ mapM_C (liftIO . putStrLn . encodeString)++        "find-conduit" -> do+            putStrLn "Running findFiles from find-conduit"+            findFiles defaultFindOptions { findFollowSymlinks = False }+                (decodeString dir) $ do+                    path <- asks entryPath+                    guard (".hs" `isSuffixOf` path)+                    norecurse+                    liftIO $ putStrLn path++        "find-conduit2" -> do+            putStrLn "Running findFiles from find-conduit"+            runResourceT $+                sourceFindFiles defaultFindOptions { findFollowSymlinks = False }+                    (decodeString dir) (return ())+                    =$ filterC ((".hs" `isSuffixOf`) . entryPath . fst)+                    $$ mapM_C (liftIO . putStrLn . entryPath . fst)++        "find" -> do+            putStrLn "Running GNU find"+            executeFile "find" True [dir, "-name", "*.hs", "-print"] Nothing