-- -- Copyright (c) 2012 Mark Dittmer - http://www.markdittmer.org -- Developed for a Google Summer of Code project - http://gsoc2012.markdittmer.org -- {-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-} module System.FSNotify.Path ( findFiles , findDirs , canonicalizeDirPath , canonicalizePath , hasThisExtension ) where import Prelude hiding (FilePath) import Control.Applicative import Control.Monad -- import Filesystem -- import Filesystem.Path hiding (concat) import qualified Data.Text as T import qualified System.Directory as D import System.PosixCompat.Files as PF import System.FilePath getDirectoryContentsPath :: FilePath -> IO [FilePath] getDirectoryContentsPath path = (map (path )) . filter (not . dots) <$> D.getDirectoryContents path where dots "." = True dots ".." = True dots _ = False fileDirContents :: FilePath -> IO ([FilePath],[FilePath]) fileDirContents path = do contents <- getDirectoryContentsPath path stats <- mapM getFileStatus contents let pairs = zip stats contents let files = [ f | (s, f) <- pairs, PF.isRegularFile s] let dirs = [ d | (s, d) <- pairs, PF.isDirectory s] return (files, dirs) findAllFiles :: FilePath -> IO [FilePath] findAllFiles path = do (files, dirs) <- fileDirContents path nestedFiles <- mapM findAllFiles dirs return (files ++ concat nestedFiles) findImmediateFiles, findImmediateDirs :: FilePath -> IO [FilePath] findImmediateFiles = fileDirContents >=> mapM D.canonicalizePath . fst findImmediateDirs = fileDirContents >=> mapM D.canonicalizePath . snd findAllDirs :: FilePath -> IO [FilePath] findAllDirs path = do dirs <- findImmediateDirs path nestedDirs <- mapM findAllDirs dirs return (dirs ++ concat nestedDirs) findFiles :: Bool -> FilePath -> IO [FilePath] findFiles True path = findAllFiles =<< canonicalizeDirPath path findFiles False path = findImmediateFiles =<< canonicalizeDirPath path findDirs :: Bool -> FilePath -> IO [FilePath] findDirs True path = findAllDirs =<< canonicalizeDirPath path findDirs False path = findImmediateDirs =<< canonicalizeDirPath path -- | add a trailing slash to ensure the path indicates a directory addTrailingSlash :: FilePath -> FilePath addTrailingSlash = addTrailingPathSeparator canonicalizeDirPath :: FilePath -> IO FilePath canonicalizeDirPath path = addTrailingSlash `fmap` D.canonicalizePath path -- | bugfix older version of canonicalizePath (system-fileio <= 0.3.7) loses trailing slash canonicalizePath :: FilePath -> IO FilePath canonicalizePath path = let was_dir = null (takeFileName path) in if not was_dir then D.canonicalizePath path else canonicalizeDirPath path hasThisExtension :: FilePath -> T.Text -> Bool hasThisExtension p ext = takeExtension p == T.unpack ext