packages feed

git-phoenix-0.0.1: src/Data/Git/Phoenix/Commit.hs

module Data.Git.Phoenix.Commit where

import Data.ByteString.Lazy qualified as L
import Data.ByteString.Lazy.Char8 qualified as L8
import Data.Time
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
-- import Data.Time.Format.Internal
import Data.Word8 qualified as W
import Relude

type LbsPair = (LByteString, LByteString)

extractField ::
  Word8 -> LByteString -> (LByteString -> LbsPair) -> LByteString -> LbsPair
extractField b field parseValue bs =
  case L.dropWhile (/= b) bs of
    "" -> ("", "")
    bs' ->
      if field `L.isPrefixOf` bs'
      then parseValue $ L.drop (L.length field) bs'
      else extractField b field parseValue $ L.drop 1 bs'

extractParent :: L.ByteString -> LbsPair
extractParent =
  extractField W._lf "\nparent " (L.span W.isHexDigit)

extractAuthor :: LByteString -> LbsPair
extractAuthor =
  extractField W._lf "\nauthor " (L.span (/= W._less))

extractCommitTs :: LByteString -> Maybe (Int64, LByteString)
extractCommitTs bs =
  case extractField W._greater "> " (L.span (/= W._lf)) bs of
    (tsBs, bs') ->
      case L8.readInt64 tsBs of
        Nothing -> Nothing
        Just (epoch', spcTzBs) ->
          case L8.readInt64 $ L.dropWhile W.isSpace spcTzBs of
            Nothing -> Nothing
            Just (tz, _) ->
              let
                tzAbs = abs tz
                (tzH, tzM) = tzAbs `divMod` 100
              in
                Just (epoch' + (tzH * 3600 + tzM * 60) * signum tz, bs')

extractMessage :: LByteString -> LByteString
extractMessage bs =
  case extractField W._lf "\n\n" (L.span (/= W._lf)) bs of
    (msgFirstLine, _) -> msgFirstLine

extractTreeHash :: LByteString -> LbsPair
extractTreeHash =
  extractField 0 "\0tree " (L.span W.isHexDigit)

epoch :: UTCTime
epoch = posixSecondsToUTCTime 0
{-# INLINE epoch #-}

secondsToUtcTime :: Integer -> UTCTime
secondsToUtcTime x = addUTCTime (realToFrac $ picosecondsToDiffTime (x * 1000000000000)) epoch