filepather (empty) → 0.3.0
raw patch · 10 files changed
+817/−0 lines, 10 filesdep +basedep +comonaddep +comonad-transformerssetup-changed
Dependencies added: base, comonad, comonad-transformers, data-lens, directory, filepath, mtl, transformers
Files
- LICENSE +27/−0
- Setup.hs +3/−0
- filepather.cabal +48/−0
- src/System/FilePath/FilePather.hs +9/−0
- src/System/FilePath/FilePather/FilePathPredicate.hs +270/−0
- src/System/FilePath/FilePather/FileType.hs +32/−0
- src/System/FilePath/FilePather/FilterPredicate.hs +88/−0
- src/System/FilePath/FilePather/Find.hs +255/−0
- src/System/FilePath/FilePather/LiftI.hs +26/−0
- src/System/FilePath/FilePather/RecursePredicate.hs +59/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright 2012-2014 Tony Morris++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple+main = defaultMain+
+ filepather.cabal view
@@ -0,0 +1,48 @@+Name: filepather+Version: 0.3.0+Author: Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>+Maintainer: Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>+Copyright: Tony Morris+License: BSD3+License-File: LICENSE+Synopsis: Functions on System.FilePath+Category: System+Description:+ Functions over @System.FilePath@ including a find function for recursing down directories.+Homepage: https://github.com/tonymorris/filepather+Cabal-version: >= 1.6+Build-Type: Simple++Flag small_base+ Description: Choose the new, split-up base package.++Library+ Build-Depends:+ base < 5 && >= 3,+ directory >= 1.1,+ filepath >= 1.2,+ mtl >= 2,+ comonad >= 1.1,+ transformers >= 0.2,+ data-lens >= 2.9,+ comonad-transformers >= 2++ GHC-Options:+ -Wall++ Hs-Source-Dirs:+ src++ Exposed-Modules:+ System.FilePath.FilePather+ System.FilePath.FilePather.FileType+ System.FilePath.FilePather.RecursePredicate+ System.FilePath.FilePather.FilterPredicate+ System.FilePath.FilePather.FilePathPredicate+ System.FilePath.FilePather.Find+ System.FilePath.FilePather.LiftI++Source-Repository head+ type: git+ location: git@github.com:tonymorris/filepather.git+
+ src/System/FilePath/FilePather.hs view
@@ -0,0 +1,9 @@+module System.FilePath.FilePather(module X) where++import System.FilePath.FilePather.FileType as X+import System.FilePath.FilePather.RecursePredicate as X+import System.FilePath.FilePather.FilterPredicate as X+import System.FilePath.FilePather.FilePathPredicate as X+import System.FilePath.FilePather.Find as X+import System.FilePath.FilePather.LiftI as X+
+ src/System/FilePath/FilePather/FilePathPredicate.hs view
@@ -0,0 +1,270 @@+module System.FilePath.FilePather.FilePathPredicate+(+ FilePathPredicate(..)+) where++import qualified System.FilePath as P+import System.FilePath.FilePather.RecursePredicate+import System.FilePath.FilePather.FilterPredicate+import Control.Monad+import qualified Data.Foldable as F++-- | Functions that are common to predicates that work on 'FilePath' values.+class FilePathPredicate f where+ -- | A predicate that always succeeds.+ always ::+ Monad g =>+ f g+ -- | A predicate that always fails.+ never ::+ Monad g =>+ f g+ -- | Return a predicate that succeeds only if the two given predicates succeed.+ (.&&.) ::+ Monad g =>+ f g+ -> f g+ -> f g+ -- | Return a predicate that succeeds if any of the two given predicates succeed.+ (.||.) ::+ Monad g =>+ f g+ -> f g+ -> f g+ -- | Negates the given predicate.+ (.!.) ::+ Monad g =>+ f g+ -> f g+ -- | Folds the predicates on disjunction.+ anyof ::+ (F.Foldable t, Monad g) =>+ t (f g)+ -> f g+ -- | Folds the predicates on conjunction.+ anyof =+ F.foldr (.||.) never+ allof ::+ (F.Foldable t, Monad g) =>+ t (f g)+ -> f g+ allof =+ F.foldr (.&&.) always+ -- | A predicate that computes its result based on a file name extension.+ extension ::+ Monad g =>+ (FilePath -> Bool)+ -> f g+ -- | A predicate that computes its result based on equivalence to a file name extension. This function matches with and without the preceding extension separator (.).+ extensionEq ::+ Monad g =>+ FilePath+ -> f g+ extensionEq p =+ extension (== p)+ -- | A predicate that computes its result based on equivalence to one of a list of file name extensions.+ extensionOneof ::+ (F.Foldable t, Monad g) =>+ t FilePath+ -> f g+ extensionOneof =+ F.foldr (\a b -> extensionEq a .||. b) never+ -- | A predicate that computes its result based on inequivalence to any of a list of file name extensions.+ extensionNoneof ::+ (F.Foldable t, Monad g) =>+ t FilePath+ -> f g+ extensionNoneof =+ F.foldr (\a b -> (.!.) (extensionEq a) .&&. b) always+ -- | A predicate that computes its result based on a directory.+ directory ::+ Monad g =>+ (FilePath -> Bool)+ -> f g+ -- | A predicate that succeeds if its 'FilePath' has an extension.+ hasExtension ::+ Monad g =>+ f g+ hasExtension =+ (.!.) notHasExtension+ -- | A predicate that succeeds if its 'FilePath' does not have an extension.+ notHasExtension ::+ Monad g =>+ f g+ notHasExtension =+ (.!.) hasExtension+ -- | A predicate that computes its result based on the splitting of a name and extension.+ splitExtension ::+ Monad g =>+ (String -> String -> Bool)+ -> f g+ -- | A predicate that computes its result based on the splitting of a name into directories.+ splitDirectories ::+ Monad g =>+ ([FilePath] -> Bool)+ -> f g+ -- | A predicate that succeeds if its 'FilePath' has a trailing path separator.+ hasTrailingPathSeparator ::+ Monad g =>+ f g+ hasTrailingPathSeparator =+ (.!.) notHasTrailingPathSeparator+ -- | A predicate that succeeds if its 'FilePath' does not have a trailing path separator.+ notHasTrailingPathSeparator::+ Monad g =>+ f g+ notHasTrailingPathSeparator =+ (.!.) hasTrailingPathSeparator+ -- | A predicate that computes its result based on the file name.+ fileName ::+ Monad g =>+ (FilePath -> Bool)+ -> f g+ -- | A predicate that computes its result based on the base name.+ baseName ::+ Monad g =>+ (FilePath -> Bool)+ -> f g+ -- | A predicate that computes its result based on the normalised file name.+ normalise ::+ Monad g =>+ (FilePath -> Bool)+ -> f g+ -- | A predicate that computes its result based on the file name having been made valid.+ makeValid ::+ Monad g =>+ (FilePath -> Bool)+ -> f g+ -- | A predicate that succeeds if its 'FilePath' is relative.+ isRelative ::+ Monad g =>+ f g+ isRelative =+ (.!.) isNotRelative+ -- | A predicate that succeeds if its 'FilePath' is not relative.+ isNotRelative ::+ Monad g =>+ f g+ isNotRelative =+ (.!.) isRelative+ -- | A predicate that succeeds if its 'FilePath' is absolute.+ isAbsolute ::+ Monad g =>+ f g+ isAbsolute =+ (.!.) isNotAbsolute+ -- | A predicate that succeeds if its 'FilePath' is not absolute.+ isNotAbsolute ::+ Monad g =>+ f g+ isNotAbsolute =+ (.!.) isAbsolute+ -- | A predicate that succeeds if its 'FilePath' is valid.+ isValid ::+ Monad g =>+ f g+ isValid =+ (.!.) isNotValid+ -- | A predicate that succeeds if its 'FilePath' is not valid.+ isNotValid ::+ Monad g =>+ f g+ isNotValid =+ (.!.) isValid++instance FilePathPredicate RecursePredicateT where+ always =+ recursePredicateT . const . return $ True+ never =+ recursePredicateT . const . return $ False+ f .&&. g =+ recursePredicateT $ \p -> do r <- runRecursePredicateT f p+ if r+ then+ runRecursePredicateT g p+ else+ return False+ f .||. g =+ recursePredicateT $ \p -> do r <- runRecursePredicateT f p+ if r+ then+ return True+ else+ runRecursePredicateT g p+ (.!.) f =+ recursePredicateT $ liftM not . runRecursePredicateT f+ extension f = + recursePredicateT $ return . liftM2 (||) f (f . drop 1) . P.takeExtension+ directory f = + recursePredicateT $ return . f . P.takeDirectory+ hasExtension =+ recursePredicateT $ return . P.hasExtension+ splitExtension f =+ recursePredicateT $ return . uncurry f . P.splitExtension+ splitDirectories f = + recursePredicateT $ return . f . P.splitDirectories+ hasTrailingPathSeparator =+ recursePredicateT $ return . P.hasTrailingPathSeparator+ fileName f = + recursePredicateT $ return . f . P.takeFileName+ baseName f = + recursePredicateT $ return . f . P.takeBaseName+ normalise f = + recursePredicateT $ return . f . P.normalise+ makeValid f = + recursePredicateT $ return . f . P.makeValid+ isRelative =+ recursePredicateT $ return . P.isRelative+ isAbsolute =+ recursePredicateT $ return . P.isAbsolute+ isValid =+ recursePredicateT $ return . P.isValid++instance FilePathPredicate FilterPredicateT where+ always =+ filterPredicateT . const . const . return $ True+ never =+ filterPredicateT . const . const . return $ False+ f .&&. g =+ filterPredicateT $ \p k -> do r <- runFilterPredicateT f p k+ if r+ then+ runFilterPredicateT g p k+ else+ return False+ f .||. g =+ filterPredicateT $ \p k -> do r <- runFilterPredicateT f p k+ if r+ then+ return True+ else+ runFilterPredicateT g p k+ (.!.) f =+ filterPredicateT $ \p -> liftM not . runFilterPredicateT f p+ extension f = + filterPredicateT $ const . return . liftM2 (||) f (f . drop 1) . P.takeExtension+ directory f = + filterPredicateT $ const . return . f . P.takeDirectory+ hasExtension =+ filterPredicateT $ const . return . P.hasExtension+ splitExtension f =+ filterPredicateT $ const . return . uncurry f . P.splitExtension+ splitDirectories f = + filterPredicateT $ const . return . f . P.splitDirectories+ hasTrailingPathSeparator =+ filterPredicateT $ const . return . P.hasTrailingPathSeparator+ fileName f = + filterPredicateT $ const . return . f . P.takeFileName+ baseName f = + filterPredicateT $ const . return . f . P.takeBaseName+ normalise f = + filterPredicateT $ const . return . f . P.normalise+ makeValid f = + filterPredicateT $ const . return . f . P.makeValid+ isRelative =+ filterPredicateT $ const . return . P.isRelative+ isAbsolute =+ filterPredicateT $ const . return . P.isAbsolute+ isValid =+ filterPredicateT $ const . return . P.isValid+
+ src/System/FilePath/FilePather/FileType.hs view
@@ -0,0 +1,32 @@+module System.FilePath.FilePather.FileType+(+ FileType(..)+, isFile+, isDirectory+, isUnknown+) where+-- | The possible types of a file.+data FileType =+ File -- ^ The type is a normal file.+ | Directory -- ^ The type is a directory.+ | Unknown -- ^ The type is unknown.+ deriving (Eq, Ord, Show, Enum)++isFile ::+ FileType+ -> Bool+isFile =+ (==) File++isDirectory ::+ FileType+ -> Bool+isDirectory =+ (==) Directory++isUnknown ::+ FileType+ -> Bool+isUnknown =+ (==) Unknown+
+ src/System/FilePath/FilePather/FilterPredicate.hs view
@@ -0,0 +1,88 @@+module System.FilePath.FilePather.FilterPredicate+(+ FilterPredicateT+, FilterPredicate+, filterPredicateT+, filterPredicate+, filterPredicateT'+, filterPredicate'+, runFilterPredicateT+, runFilterPredicate+, isDirectoryType+, isFileType+, isUnknownType+) where++import Control.Monad.Identity+import System.FilePath.FilePather.FileType++newtype FilterPredicateT f =+ FilterPredicateT (FilePath -> FileType -> f Bool)++-- | A filter predicate that does not require effects to compute its result.+type FilterPredicate =+ FilterPredicateT Identity++-- | A filter predicate takes a 'FilePath' and a file type and returns whether or not to filter the value.+filterPredicateT ::+ (FilePath -> FileType -> f Bool)+ -> FilterPredicateT f+filterPredicateT =+ FilterPredicateT++-- | Construct a filter predicate that does not require effects to compute its result.+filterPredicate ::+ (FilePath -> FileType -> Bool)+ -> FilterPredicate+filterPredicate f =+ filterPredicateT (\z -> Identity . f z)++-- | A filter predicate takes a 'FilePath' and returns whether or not to filter the value.+filterPredicateT' ::+ (FilePath -> f Bool)+ -> FilterPredicateT f+filterPredicateT' f =+ filterPredicateT (const . f)++-- | Construct a filter predicate that does not require effects to compute its result.+filterPredicate' ::+ (FilePath -> Bool)+ -> FilterPredicate+filterPredicate' f =+ filterPredicate (const . f)++-- | Extract the filter predicate function.+runFilterPredicateT ::+ FilterPredicateT f+ -> FilePath+ -> FileType+ -> f Bool+runFilterPredicateT (FilterPredicateT f) =+ f++-- | Construct a filter predicate that does not require effects to compute its result.+runFilterPredicate ::+ FilterPredicate+ -> FilePath+ -> FileType+ -> Bool+runFilterPredicate p k =+ runIdentity . runFilterPredicateT p k++isDirectoryType ::+ Monad f =>+ FilterPredicateT f+isDirectoryType =+ filterPredicateT . const $ return . isDirectory++isFileType ::+ Monad f =>+ FilterPredicateT f+isFileType =+ filterPredicateT . const $ return . isFile++isUnknownType ::+ Monad f =>+ FilterPredicateT f+isUnknownType =+ filterPredicateT . const $ return . isUnknown
+ src/System/FilePath/FilePather/Find.hs view
@@ -0,0 +1,255 @@+module System.FilePath.FilePather.Find+(+ Find(..)+, findi+, findpi+, FindR+, foundR+, dropR+, recurseR+, noRecurseR+, foundL+, dropL+, recurseL+, noRecurseL+) where++import Control.Monad.Identity+import Control.Monad.Trans.Identity+import Control.Comonad+import Control.Comonad.Trans.Store+import Data.Lens.Partial.Common hiding (null)+import System.FilePath+import System.FilePath.FilePather.RecursePredicate+import System.FilePath.FilePather.FilterPredicate+import System.FilePath.FilePather.FileType+import System.Directory++class Find f where+ -- | Finds all files using the given recurse predicate and filter predicate in the given file path.+ find ::+ FilterPredicateT f+ -> RecursePredicateT f+ -> FilePath+ -> IO [FindR]+ -- | Find files in the current directory.+ findHere ::+ FilterPredicateT f+ -> RecursePredicateT f+ -> IO [FindR]+ findHere f r =+ getCurrentDirectory >>= find f r+ -- | Finds all files using the given recurse predicate and filter predicate in the given file path.+ findp ::+ FilterPredicateT f+ -> RecursePredicateT f+ -> FilePath+ -> IO [FilePath]+ findp f r =+ liftM (\x -> x >>= \w ->+ case w of+ Found p _ -> [p]+ Drop _ _ -> []+ Recurse _ -> []+ NoRecurse _ -> []) . find f r+ -- | Find files in the current directory.+ findpHere ::+ FilterPredicateT f+ -> RecursePredicateT f+ -> IO [FilePath]+ findpHere f r =+ getCurrentDirectory >>= findp f r++instance Find Identity where+ find f' r' =+ let find' base p =+ let f =+ runFilterPredicateT f'+ r =+ runRecursePredicateT r'+ z ::+ FilePath+ z =+ if null base then p else base </> p+ keep ::+ Bool+ -> FileType+ -> FindR+ keep u =+ (if u then Found else Drop) z+ rkeep ::+ Bool+ -> FindR+ rkeep u =+ (if u then Recurse else NoRecurse) z+ tkeep ::+ FileType+ -> [FindR]+ tkeep t =+ [keep (runIdentity (f z t)) t]+ in do fe <- doesFileExist z+ if fe+ then+ return (tkeep File)+ else+ do de <- doesDirectoryExist z+ if de+ then+ let (Identity k) = f z Directory+ (Identity l) = r z+ in liftM ([rkeep l, keep k Directory] ++) $+ if l+ then+ do t <- getDirectoryContents z+ u <- forM (filter (`notElem` [".", ".."]) t) (find f' r' . (z </>))+ return (concat u)+ else+ return []+ else+ return (tkeep Unknown)+ in find' []++instance Find IO where+ find f' r' =+ let find' base p =+ let f =+ runFilterPredicateT f'+ r =+ runRecursePredicateT r'+ z ::+ FilePath+ z =+ if null base then p else base </> p+ keep ::+ Bool+ -> FileType+ -> FindR+ keep u =+ (if u then Found else Drop) z+ rkeep ::+ Bool+ -> FindR+ rkeep u =+ (if u then Recurse else NoRecurse) z+ tkeep ::+ FileType+ -> IO [FindR]+ tkeep t =+ f z t >>= \y -> return [keep y t]+ in do fe <- doesFileExist z+ if fe+ then+ tkeep File+ else+ do de <- doesDirectoryExist z+ if de+ then+ do k <- f z Directory+ l <- r z+ liftM ([rkeep l, keep k Directory] ++) $+ if l+ then+ do t <- getDirectoryContents z+ u <- forM (filter (`notElem` [".", ".."]) t) (find f' r' . (z </>))+ return (concat u)+ else+ return []+ else+ tkeep Unknown+ in find' []++instance Comonad f => Find (IdentityT f) where+ find f r =+ find (filterPredicateT $ \p -> Identity . extract . runFilterPredicateT f p) (recursePredicateT $ Identity . extract . runRecursePredicateT r)++-- | A specialisation of `find` to the `Identity` monad. Useful in assisting type-inference.+findi ::+ FilterPredicate+ -> RecursePredicate+ -> FilePath+ -> IO [FindR]+findi =+ find++-- | A specialisation of `findp` to the `Identity` monad. Useful in assisting type-inference.+findpi ::+ FilterPredicate+ -> RecursePredicate+ -> FilePath+ -> IO [FilePath]+findpi =+ findp++-- | The results of a path find. One of+--+-- * @found@ with the file path name and file type.+--+-- * @drop@ with the file path name and file type.+--+-- * @recurse@ with the file path (the file type is always directory).+--+-- * @no-recurse@ with the file path (the file type is always directory).+data FindR =+ Found FilePath FileType+ | Drop FilePath FileType+ | Recurse FilePath+ | NoRecurse FilePath+ deriving (Eq, Show)++foundR ::+ FilePath+ -> FileType+ -> FindR+foundR =+ Found++dropR ::+ FilePath+ -> FileType+ -> FindR+dropR =+ Drop++recurseR ::+ FilePath+ -> FindR+recurseR =+ Recurse++noRecurseR ::+ FilePath+ -> FindR+noRecurseR =+ NoRecurse++foundL ::+ PartialLens FindR (FilePath, FileType)+foundL =+ PLens $ \r ->+ case r of+ Found p t -> Just (store (uncurry Found) (p, t))+ _ -> Nothing++dropL ::+ PartialLens FindR (FilePath, FileType)+dropL =+ PLens $ \r ->+ case r of+ Drop p t -> Just (store (uncurry Drop) (p, t))+ _ -> Nothing++recurseL ::+ PartialLens FindR FilePath+recurseL =+ PLens $ \r ->+ case r of+ Recurse p -> Just (store Recurse p)+ _ -> Nothing++noRecurseL ::+ PartialLens FindR FilePath+noRecurseL =+ PLens $ \r ->+ case r of+ NoRecurse p -> Just (store NoRecurse p)+ _ -> Nothing
+ src/System/FilePath/FilePather/LiftI.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}++module System.FilePath.FilePather.LiftI+(+ LiftI(..)+) where++import System.FilePath.FilePather.RecursePredicate+import System.FilePath.FilePather.FilterPredicate++-- | A type-class for lifting a value.+-- This type-class probably belongs elsewhere (pointers appreciated!).+class LiftI f a | f -> a where+ liftI ::+ Monad g =>+ g a+ -> f g++instance LiftI RecursePredicateT Bool where+ liftI = + recursePredicateT . const++instance LiftI FilterPredicateT Bool where+ liftI = + filterPredicateT . const . const+
+ src/System/FilePath/FilePather/RecursePredicate.hs view
@@ -0,0 +1,59 @@+module System.FilePath.FilePather.RecursePredicate+(+ RecursePredicateT+, RecursePredicate+, recursePredicateT+, recursePredicate+, runRecursePredicateT+, runRecursePredicate+, toFilterPredicate+) where++import Control.Monad.Identity+import System.FilePath.FilePather.FilterPredicate++-- | A recurse predicate takes a 'FilePath', which is a directory, and returns whether or not to continue recursing down on that directory.+newtype RecursePredicateT f =+ RecursePredicateT (FilePath -> f Bool)++-- | A recurse predicate that does not require effects to compute its result.+type RecursePredicate =+ RecursePredicateT Identity++-- | Construct a recurse predicate. The most general construction function.+recursePredicateT ::+ (FilePath -> f Bool)+ -> RecursePredicateT f+recursePredicateT =+ RecursePredicateT++-- | Construct a recurse predicate that does not require effects to compute its result.+recursePredicate ::+ (FilePath -> Bool)+ -> RecursePredicate+recursePredicate f =+ recursePredicateT (Identity . f)++-- | Extract the recurse predicate function.+runRecursePredicateT ::+ RecursePredicateT f+ -> FilePath+ -> f Bool+runRecursePredicateT (RecursePredicateT f) =+ f++-- | Extract the recurse predicate function that does not require effects to compute its result.+runRecursePredicate ::+ RecursePredicate+ -> FilePath+ -> Bool+runRecursePredicate p =+ runIdentity . runRecursePredicateT p++-- | Convert the recurse predicate to a filter predicate.+toFilterPredicate ::+ RecursePredicateT f+ -> FilterPredicateT f+toFilterPredicate (RecursePredicateT f) =+ filterPredicateT (const . f)+