module Hackage.Utils where

import Distribution.Package
         ( Dependency(..) )
import Distribution.Text
         ( display )
import Distribution.Simple.Utils (intercalate)

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

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

Add new utils, duplicates, duplicatesBy and mergeBy
Add new utils, duplicates, duplicatesBy and mergeBy
