{-# LANGUAGE ScopedTypeVariables #-}
module Retrie.Util where
import Control.Applicative
import Control.Concurrent.Async
import Control.Exception
import Control.Monad
import Data.List
import System.Exit
import System.FilePath
import System.Process
data Verbosity = Silent | Normal | Loud
deriving (Eq, Ord, Show)
debugPrint :: Verbosity -> String -> [String] -> IO ()
debugPrint verbosity header ls
| verbosity < Loud = return ()
| otherwise = mapM_ putStrLn (header:ls)
vcsIgnorePred :: Verbosity -> FilePath -> IO (Maybe (FilePath -> Bool))
vcsIgnorePred verbosity fp = do
(gitPred, hgPred) <-
concurrently (gitIgnorePred verbosity fp) (hgIgnorePred verbosity fp)
return $ gitPred <|> hgPred
gitIgnorePred :: Verbosity -> FilePath -> IO (Maybe (FilePath -> Bool))
gitIgnorePred verbosity targetDir = ignoreWorker "gitIgnorePred: " verbosity targetDir id $
proc "git"
[ "ls-files"
, "--ignored"
, "--exclude-standard"
, "--others"
, "--directory"
, targetDir
]
hgIgnorePred :: Verbosity -> FilePath -> IO (Maybe (FilePath -> Bool))
hgIgnorePred verbosity targetDir =
ignoreWorker "hgIgnorePred: " verbosity targetDir (normalise (targetDir </> ".hg") :) $
proc "hg"
[ "status"
, "--ignored"
, "--no-status"
, "-I"
, "re:.*\\.hs$"
]
ignoreWorker
:: String
-> Verbosity
-> FilePath
-> ([FilePath] -> [FilePath])
-> CreateProcess
-> IO (Maybe (FilePath -> Bool))
ignoreWorker prefix verbosity targetDir extraDirs cmd = handle (handler prefix verbosity) $ do
let command = cmd { cwd = Just targetDir }
(ec, fps, err) <- readCreateProcessWithExitCode command ""
case ec of
ExitSuccess -> do
let
(ifiles, dirs) = partition hasExtension
[ normalise $ targetDir </> dropTrailingPathSeparator f
| f <- lines fps ]
idirs = extraDirs dirs
return $ Just $ \fp -> fp `elem` ifiles || any (`isPrefixOf` fp) idirs
ExitFailure _ -> do
when (verbosity > Normal) $ putStrLn $ prefix ++ err
return Nothing
handler :: String -> Verbosity -> IOError -> IO (Maybe a)
handler prefix verbosity err = do
when (verbosity > Normal) $ putStrLn $ prefix ++ show err
return Nothing
trySync :: IO a -> IO (Either SomeException a)
trySync io = catch (Right <$> io) $ \e ->
case fromException e of
Just (_ :: SomeAsyncException) -> throwIO e
Nothing -> return (Left e)