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 +16/−0
- Data/Conduit/Find.hs +186/−116
- find-conduit.cabal +47/−9
- test/doctest.hs +0/−1
- test/find-hs.hs +42/−0
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