packages feed

MicroCabal-0.2.1.0: src/MicroCabal/Glob.hs

module MicroCabal.Glob(
  GlobPattern,
  --glob,
  listDirectoryRecursive,
  matchFiles,
  ) where
import Control.Exception
import Control.Monad
import System.Directory
import MicroCabal.Regex
import MicroCabal.Unix((</>))

-- A glob pattern can contain:
--  *   - any number of file name characters, except /
--  **  - any number of file name characters
--  X   - anything else is a character that just matches itself
type GlobPattern = String

{-
glob :: GlobPattern -> [String] -> [String]
glob p ss =
  let r = globToRegex p
  in  filter (regexMatch r) ss
-}

globToRegex :: GlobPattern -> Regex
globToRegex [] = eps
globToRegex ('*':'*':cs) = Star (Lit (Neg "")) `Seq` globToRegex cs
globToRegex ('*':cs) = Star (Lit (Neg "/")) `Seq` globToRegex cs
globToRegex (c:cs) = Lit (Pos [c]) `Seq` globToRegex cs

-- Recursively find all files in the given directory.
listDirectoryRecursive :: FilePath -> IO [FilePath]
listDirectoryRecursive ".git" = return []  -- Hack to avoid the gazillion files in .git/
listDirectoryRecursive x = do
  xs <- listDirectory x `catch` (\ (_ :: SomeException) -> return [])
  concat <$> (forM xs $ \ y -> (y:) <$> fmap (y </>) <$> listDirectoryRecursive (x </> y))

matchFiles :: FilePath -> [GlobPattern] -> IO [FilePath]
matchFiles dir pats = do
  fs <- listDirectoryRecursive dir
  let select pat =
        let re = globToRegex pat
        in  filter (regexMatch re) fs
  pure $ concatMap select pats