module Language.Haskell.Source.Enumerator (enumeratePath, HaskellSourceFilePath) where import Control.Applicative import Control.Monad import Data.List import Distribution.PackageDescription import Distribution.PackageDescription.Parse import qualified Distribution.Verbosity as Verbosity import Pipes import System.Directory import System.FilePath type HaskellSourceFilePath = FilePath enumeratePath :: FilePath -> Producer HaskellSourceFilePath IO () enumeratePath = filePath filePath :: FilePath -> Producer HaskellSourceFilePath IO () filePath path = do isCabal <- lift $ isCabalFile path if isCabal then package' path else directoryOrFile path simpleFilePath :: FilePath -> Producer HaskellSourceFilePath IO () simpleFilePath path = do isHaskellSource <- lift $ isHaskellSourceFile path when isHaskellSource $ yield path simpleDirectory :: FilePath -> Producer HaskellSourceFilePath IO () simpleDirectory path = do contents <- lift $ getDirectoryContentsFullPaths path mapM_ simpleFileOrDirectory contents simpleFileOrDirectory :: FilePath -> Producer HaskellSourceFilePath IO () simpleFileOrDirectory filepath = do dir <- lift $ doesDirectoryExist filepath if dir then simpleDirectory filepath else simpleFilePath filepath package' :: FilePath -> Producer HaskellSourceFilePath IO () package' path = readPackage path >>= expandPaths where readPackage = lift . readPackageDescription Verbosity.silent expandPaths = mapM_ (simpleFileOrDirectory . mkFull) . sourcePaths dir = dropFileName path mkFull = (dir </>) directory :: FilePath -> Producer HaskellSourceFilePath IO () directory path = do contents <- lift $ getDirectoryContentsFullPaths path cabalFiles <- lift $ filterM isCabalFile contents if null cabalFiles then mapM_ directoryOrFile contents else mapM_ package' cabalFiles directoryOrFile :: FilePath -> Producer HaskellSourceFilePath IO () directoryOrFile path = do isFile <- lift $ doesFileExist path if isFile then simpleFilePath path else directory path getDirectoryContentsFullPaths :: FilePath -> IO [FilePath] getDirectoryContentsFullPaths path = mkFull . notHidden . notMeta <$> getDirectoryContents path where mkFull = map (path </>) notHidden = filter (not . isPrefixOf ".") notMeta = (\\ [".", ".."]) isCabalFile :: FilePath -> IO Bool isCabalFile path = (hasCabalExtension &&) <$> isFile where isFile = doesFileExist path hasCabalExtension = ".cabal" `isSuffixOf` path isHaskellSourceFile :: FilePath -> IO Bool isHaskellSourceFile path = (hasHaskellExtension &&) <$> isFile where isFile = doesFileExist path hasHaskellExtension = ".hs" `isSuffixOf` path || ".lhs" `isSuffixOf` path sourcePaths :: GenericPackageDescription -> [FilePath] sourcePaths pkg = nub $ concatMap ($ pkg) pathExtractors where pathExtractors = [ maybe [] (hsSourceDirs . libBuildInfo . condTreeData) . condLibrary , concatMap (hsSourceDirs . buildInfo . condTreeData . snd) . condExecutables , concatMap (hsSourceDirs . testBuildInfo . condTreeData . snd) . condTestSuites , concatMap (hsSourceDirs . benchmarkBuildInfo . condTreeData . snd) . condBenchmarks ]