{-# LANGUAGE OverloadedStrings #-}
module HaskellCI.GitConfig (
    GitConfig (..),
    emptyGitConfig,
    readGitConfig,
) where

import HaskellCI.Prelude

import Data.Ini

import qualified Data.Attoparsec.Text as Atto
import qualified Data.Map.Strict      as Map

newtype GitConfig = GitConfig
    { gitCfgRemotes :: Map.Map Text Text
    }
  deriving Show

emptyGitConfig :: GitConfig
emptyGitConfig = GitConfig
    { gitCfgRemotes = mempty
    }

-- | Read 'GitConfig'. On error, return 'emptyGitConfg'.
readGitConfig :: IO GitConfig
readGitConfig = handle fallback $ do
    e <- readIniFile ".git/config"
    return $ case e of
        Left _    -> emptyGitConfig
        Right ini -> elaborateGitConfig ini
  where
    fallback :: IOException -> IO GitConfig
    fallback _ = return emptyGitConfig

elaborateGitConfig :: Ini -> GitConfig
elaborateGitConfig ini = ifoldr go emptyGitConfig (iniSections ini) where
    go :: Text -> [(Text, Text)] -> GitConfig -> GitConfig
    go secname secfields cfg
        | Right name <- Atto.parseOnly (sectionP <* Atto.endOfInput) secname
        , Just url   <- lookup "url" secfields
        = cfg
            { gitCfgRemotes = Map.insert name url (gitCfgRemotes cfg)
            }

    go _ _ cfg = cfg

-- We use attoparsec here, because it backtracks
sectionP :: Atto.Parser Text
sectionP = do
    _ <- Atto.string "remote"
    Atto.skipSpace
    _ <- Atto.char '"'
    remote <- Atto.takeWhile (/= '"')
    _ <- Atto.char '"'
    return remote

