    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE RecordWildCards #-}
    {-# LANGUAGE ViewPatterns #-}
    module Hpack.CabalFile where

    import           Imports

    import           Data.Maybe
    import           Data.Version (Version(..))
    import qualified Data.Version as Version
    import           Text.ParserCombinators.ReadP

    import           Hpack.Util

    makeVersion :: [Int] -> Version
    makeVersion :: [Int] -> Version
    makeVersion [Int]
    v = [Int] -> [String] -> Version
    Version [Int]
    v []

    data CabalFile = CabalFile {
      CabalFile -> [String]
    cabalFileCabalVersion :: [String]
    , CabalFile -> Maybe Version
    cabalFileHpackVersion :: Maybe Version
    , CabalFile -> Maybe String
    cabalFileHash :: Maybe Hash
    , CabalFile -> [String]
    cabalFileContents :: [String]
    } deriving (CabalFile -> CabalFile -> Bool
    (CabalFile -> CabalFile -> Bool)
    -> (CabalFile -> CabalFile -> Bool) -> Eq CabalFile
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: CabalFile -> CabalFile -> Bool
    == :: CabalFile -> CabalFile -> Bool
    $c/= :: CabalFile -> CabalFile -> Bool
    /= :: CabalFile -> CabalFile -> Bool
    Eq, Int -> CabalFile -> ShowS
    [CabalFile] -> ShowS
    CabalFile -> String
    (Int -> CabalFile -> ShowS)
    -> (CabalFile -> String)
    -> ([CabalFile] -> ShowS)
    -> Show CabalFile
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> CabalFile -> ShowS
    showsPrec :: Int -> CabalFile -> ShowS
    $cshow :: CabalFile -> String
    show :: CabalFile -> String
    $cshowList :: [CabalFile] -> ShowS
    showList :: [CabalFile] -> ShowS
    Show)

    readCabalFile :: FilePath -> IO (Maybe CabalFile)
    readCabalFile :: String -> IO (Maybe CabalFile)
    readCabalFile String
    cabalFile = (String -> CabalFile) -> Maybe String -> Maybe CabalFile
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap String -> CabalFile
    parse (Maybe String -> Maybe CabalFile)
    -> IO (Maybe String) -> IO (Maybe CabalFile)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> IO (Maybe String)
    tryReadFile String
    cabalFile
      where
        parse :: String -> CabalFile
        parse :: String -> CabalFile
    parse (String -> ([String], [String], [String])
    splitHeader -> ([String]
    cabalVersion, [String]
    h, [String]
    c)) = [String] -> Maybe Version -> Maybe String -> [String] -> CabalFile
    CabalFile [String]
    cabalVersion ([String] -> Maybe Version
    extractVersion [String]
    h) ([String] -> Maybe String
    extractHash [String]
    h) [String]
    c

        splitHeader :: String -> ([String], [String], [String])
        splitHeader :: String -> ([String], [String], [String])
    splitHeader ([String] -> [String]
    removeGitConflictMarkers ([String] -> [String])
    -> (String -> [String]) -> String -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    lines -> [String]
    c) =
          case (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    span (Bool -> Bool
    not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Bool
    isComment) [String]
    c of
            ([String]
    cabalVersion, [String]
    xs) -> case (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    span String -> Bool
    isComment [String]
    xs of
              ([String]
    header, [String]
    body) -> ([String]
    cabalVersion, [String]
    header, (String -> Bool) -> [String] -> [String]
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhile String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [String]
    body)

        isComment :: String -> Bool
    isComment = (String
    "--" String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf`)

    extractHash :: [String] -> Maybe Hash
    extractHash :: [String] -> Maybe String
    extractHash = String -> (String -> Maybe String) -> [String] -> Maybe String
    forall a. String -> (String -> Maybe a) -> [String] -> Maybe a
    extract String
    "-- hash: " String -> Maybe String
    forall a. a -> Maybe a
    Just

    extractVersion :: [String] -> Maybe Version
    extractVersion :: [String] -> Maybe Version
    extractVersion = String -> (String -> Maybe Version) -> [String] -> Maybe Version
    forall a. String -> (String -> Maybe a) -> [String] -> Maybe a
    extract String
    prefix (String -> Maybe String
    stripFileName (String -> Maybe String)
    -> (String -> Maybe Version) -> String -> Maybe Version
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> String -> Maybe Version
    parseVersion (String -> Maybe Version) -> ShowS -> String -> Maybe Version
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ShowS
    forall a. [a] -> [a]
    safeInit)
      where
        prefix :: String
    prefix = String
    "-- This file has been generated from "
        stripFileName :: String -> Maybe String
        stripFileName :: String -> Maybe String
    stripFileName = [String] -> Maybe String
    forall a. [a] -> Maybe a
    listToMaybe ([String] -> Maybe String)
    -> (String -> [String]) -> String -> Maybe String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> Maybe String) -> [String] -> [String]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe (String -> String -> Maybe String
    forall a. Eq a => [a] -> [a] -> Maybe [a]
    stripPrefix String
    " by hpack version ") ([String] -> [String])
    -> (String -> [String]) -> String -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    forall a. [a] -> [[a]]
    tails

    extract :: String -> (String -> Maybe a) -> [String] -> Maybe a
    extract :: forall a. String -> (String -> Maybe a) -> [String] -> Maybe a
    extract String
    prefix String -> Maybe a
    parse = [a] -> Maybe a
    forall a. [a] -> Maybe a
    listToMaybe ([a] -> Maybe a) -> ([String] -> [a]) -> [String] -> Maybe a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> Maybe a) -> [String] -> [a]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe (String -> String -> Maybe String
    forall a. Eq a => [a] -> [a] -> Maybe [a]
    stripPrefix String
    prefix (String -> Maybe String)
    -> (String -> Maybe a) -> String -> Maybe a
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> String -> Maybe a
    parse)

    safeInit :: [a] -> [a]
    safeInit :: forall a. [a] -> [a]
    safeInit [] = []
    safeInit [a]
    xs = [a] -> [a]
    forall a. HasCallStack => [a] -> [a]
    init [a]
    xs

    parseVersion :: String -> Maybe Version
    parseVersion :: String -> Maybe Version
    parseVersion String
    xs = case [Version
    v | (Version
    v, String
    "") <- ReadP Version -> ReadS Version
    forall a. ReadP a -> ReadS a
    readP_to_S ReadP Version
    Version.parseVersion String
    xs] of
      [Version
    v] -> Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    v
      [Version]
    _ -> Maybe Version
    forall a. Maybe a
    Nothing

    removeGitConflictMarkers :: [String] -> [String]
    removeGitConflictMarkers :: [String] -> [String]
    removeGitConflictMarkers = [String] -> [String]
    takeBoth
      where
        takeBoth :: [String] -> [String]
    takeBoth [String]
    input = case (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    isPrefixOf String
    marker) [String]
    input of
          ([String]
    both, String
    _marker : [String]
    rest) -> [String]
    both [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String] -> [String]
    takeOurs [String]
    rest
          ([String]
    both, []) -> [String]
    both
          where
            marker :: String
    marker = String
    "<<<<<<< "

        takeOurs :: [String] -> [String]
    takeOurs [String]
    input = case (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    marker) [String]
    input of
          ([String]
    ours, String
    _marker : [String]
    rest) -> [String]
    ours [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String] -> [String]
    dropTheirs [String]
    rest
          ([String]
    ours, []) -> [String]
    ours
          where
            marker :: String
    marker = String
    "======="

        dropTheirs :: [String] -> [String]
    dropTheirs [String]
    input = case (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    isPrefixOf String
    marker) [String]
    input of
          ([String]
    _theirs, String
    _marker : [String]
    rest) -> [String] -> [String]
    takeBoth [String]
    rest
          ([String]
    _theirs, []) -> []
          where
            marker :: String
    marker = String
    ">>>>>>> "