-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add some globbing for copying files.
- Loading branch information
Showing
4 changed files
with
158 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
-- Originally stolen from https://crypto.stanford.edu/~blynn/haskell/re.html | ||
|
||
-- Regular expression matching using Brzozowski's algorithm | ||
module MicroCabal.Regex(CharClass(..), Regex(..), eps, regexMatch) where | ||
import Data.List(sort, nub) | ||
|
||
data CharClass = Pos String | Neg String | ||
deriving (Eq, Ord, Show) | ||
|
||
elemCC :: Char -> CharClass -> Bool | ||
elemCC c (Pos cs) = c `elem` cs | ||
elemCC c (Neg cs) = c `notElem` cs | ||
|
||
data Regex | ||
= Lit CharClass | ||
| Seq Regex Regex | ||
| Star Regex | ||
| Or [Regex] | ||
| And [Regex] | ||
| Not Regex | ||
deriving (Eq, Ord, Show) | ||
|
||
regexMatch :: Regex -> String -> Bool | ||
regexMatch re "" = nullable re | ||
regexMatch re (c:s) = regexMatch (derive c re) s | ||
|
||
-- The regex `()`. The language containing only the empty string. | ||
eps :: Regex | ||
eps = Star noGood | ||
|
||
-- The regex `[]`. The empty language. | ||
noGood :: Regex | ||
noGood = Lit $ Pos [] | ||
|
||
-- The regex `.*`. The language containing everything. | ||
allGood :: Regex | ||
allGood = Star $ Lit $ Neg [] | ||
|
||
nullable :: Regex -> Bool | ||
nullable re = | ||
case re of | ||
Lit _ -> False | ||
Star _ -> True | ||
Seq r s -> nullable r && nullable s | ||
Or rs -> any nullable rs | ||
And rs -> all nullable rs | ||
Not r -> not $ nullable r | ||
|
||
derive :: Char -> Regex -> Regex | ||
derive c re = | ||
case re of | ||
Lit cc | elemCC c cc -> eps | ||
| otherwise -> noGood | ||
Star r -> derive c r `mkSeq` mkStar r | ||
r `Seq` s | nullable r -> mkOr [derive c r `mkSeq` s, derive c s] | ||
| otherwise -> derive c r `mkSeq` s | ||
And rs -> mkAnd $ map (derive c) rs | ||
Or rs -> mkOr $ map (derive c) rs | ||
Not r -> mkNot $ derive c r | ||
|
||
-- Smart constructors | ||
mkSeq :: Regex -> Regex -> Regex | ||
mkSeq r s | ||
| r == noGood || s == noGood = noGood | ||
| r == eps = s | ||
| s == eps = r | ||
| x `Seq` y <- r = x `mkSeq` (y `mkSeq` s) | ||
| otherwise = r `Seq` s | ||
|
||
mkOr :: [Regex] -> Regex | ||
mkOr xs | ||
| allGood `elem` zs = allGood | ||
| null zs = noGood | ||
| [z] <- zs = z | ||
| otherwise = Or zs | ||
where | ||
zs = nub $ sort $ filter (/= noGood) flat | ||
flat = concatMap deOr xs | ||
deOr (Or rs) = rs | ||
deOr r = [r] | ||
|
||
mkAnd :: [Regex] -> Regex | ||
mkAnd xs | ||
| noGood `elem` zs = noGood | ||
| null zs = allGood | ||
| [z] <- zs = z | ||
| otherwise = And zs | ||
where | ||
zs = nub $ sort $ filter (/= allGood) flat | ||
flat = concatMap deAnd xs | ||
deAnd (And rs) = rs | ||
deAnd r = [r] | ||
|
||
mkStar :: Regex -> Regex | ||
mkStar (Star s) = mkStar s | ||
mkStar r = Star r | ||
|
||
mkNot :: Regex -> Regex | ||
mkNot (Lit (Pos [])) = allGood | ||
mkNot (Not s) = s | ||
mkNot r = Not r |