module Hackage.Utils where
import Distribution.Package
( Dependency(..) )
import Distribution.Text
( display )
import Distribution.Simple.Utils (intercalate)
import Data.List
( sortBy, groupBy )
import Control.Monad (guard)
import Control.Exception (Exception, catchJust, ioErrors)
import System.IO.Error (isDoesNotExistError)
readFileIfExists :: FilePath -> IO (Maybe String)
readFileIfExists path =
catchJust fileNotFoundExceptions
(fmap Just (readFile path))
(\_ -> return Nothing)
fileNotFoundExceptions :: Exception -> Maybe IOError
fileNotFoundExceptions e =
ioErrors e >>= \ioe -> guard (isDoesNotExistError ioe) >> return ioe
showDependencies :: [Dependency] -> String
showDependencies = intercalate ", " . map display
-- | Generic merging utility. For sorted input lists this is a full outer join.
--
-- * The result list never contains @(Nothing, Nothing)@.
--
mergeBy :: (a -> b -> Ordering) -> [a] -> [b] -> [MergeResult a b]
mergeBy cmp = merge
where
merge [] ys = [ OnlyInRight y | y <- ys]
merge xs [] = [ OnlyInLeft x | x <- xs]
merge (x:xs) (y:ys) =
case x `cmp` y of
GT -> OnlyInRight y : merge (x:xs) ys
EQ -> InBoth x y : merge xs ys
LT -> OnlyInLeft x : merge xs (y:ys)
data MergeResult a b = OnlyInLeft a | InBoth a b | OnlyInRight b
duplicates :: Ord a => [a] -> [[a]]
duplicates = duplicatesBy compare
duplicatesBy :: (a -> a -> Ordering) -> [a] -> [[a]]
duplicatesBy cmp = filter moreThanOne . groupBy eq . sortBy cmp
where
eq a b = case cmp a b of
EQ -> True
_ -> False
moreThanOne (_:_:_) = True
moreThanOne _ = False